summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/annotation/PrivateApi.java31
-rw-r--r--core/java/android/app/Activity.java7
-rw-r--r--core/java/android/app/ActivityManager.java101
-rw-r--r--core/java/android/app/ActivityManagerInternal.java28
-rw-r--r--core/java/android/app/ActivityManagerNative.java240
-rw-r--r--core/java/android/app/ActivityThread.java58
-rw-r--r--core/java/android/app/ActivityView.java368
-rw-r--r--core/java/android/app/AppOpsManager.java4
-rw-r--r--core/java/android/app/ApplicationPackageManager.java51
-rw-r--r--core/java/android/app/ContextImpl.java215
-rw-r--r--core/java/android/app/Dialog.java4
-rw-r--r--core/java/android/app/Fragment.java1
-rw-r--r--core/java/android/app/FragmentManager.java1
-rw-r--r--core/java/android/app/IActivityContainer.aidl35
-rw-r--r--core/java/android/app/IActivityContainerCallback.aidl24
-rw-r--r--core/java/android/app/IActivityManager.java39
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/IWallpaperManager.aidl10
-rw-r--r--core/java/android/app/LoadedApk.java51
-rw-r--r--core/java/android/app/Notification.java192
-rw-r--r--core/java/android/app/PendingIntent.java40
-rw-r--r--core/java/android/app/UiModeManager.java8
-rw-r--r--core/java/android/app/WallpaperManager.java66
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl4
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java303
-rw-r--r--core/java/android/bluetooth/BluetoothAdvScanData.java152
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java179
-rw-r--r--core/java/android/bluetooth/BluetoothGattCallback.java15
-rw-r--r--core/java/android/bluetooth/BluetoothGattServer.java2
-rw-r--r--core/java/android/bluetooth/BluetoothGattService.java23
-rw-r--r--core/java/android/bluetooth/BluetoothInputDevice.java26
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java27
-rw-r--r--core/java/android/bluetooth/BluetoothTetheringDataTracker.java8
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java16
-rw-r--r--core/java/android/bluetooth/IBluetoothGatt.aidl16
-rw-r--r--core/java/android/bluetooth/IBluetoothGattCallback.aidl3
-rw-r--r--core/java/android/bluetooth/package.html16
-rw-r--r--core/java/android/content/ClipDescription.java2
-rw-r--r--core/java/android/content/ContentProvider.java6
-rw-r--r--core/java/android/content/ContentResolver.java12
-rw-r--r--core/java/android/content/Context.java20
-rw-r--r--core/java/android/content/Intent.java48
-rw-r--r--core/java/android/content/pm/ActivityInfo.java9
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java10
-rw-r--r--core/java/android/content/pm/ComponentInfo.java18
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java52
-rw-r--r--core/java/android/content/pm/PackageManager.java158
-rw-r--r--core/java/android/content/pm/PackageParser.java54
-rw-r--r--core/java/android/content/res/Configuration.java10
-rw-r--r--core/java/android/content/res/Resources.java5
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java10
-rw-r--r--core/java/android/hardware/Camera.java30
-rw-r--r--core/java/android/hardware/Sensor.java208
-rw-r--r--core/java/android/hardware/SensorManager.java4
-rw-r--r--core/java/android/hardware/display/DisplayManager.java52
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java46
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java261
-rw-r--r--core/java/android/hardware/display/DisplayViewport.java77
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl26
-rw-r--r--core/java/android/hardware/display/VirtualDisplay.java43
-rw-r--r--core/java/android/hardware/hdmi/HdmiCec.java257
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecClient.java143
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecManager.java76
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecMessage.aidl19
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecMessage.java145
-rw-r--r--core/java/android/hardware/hdmi/IHdmiCecListener.aidl29
-rw-r--r--core/java/android/hardware/hdmi/IHdmiCecService.aidl40
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl11
-rw-r--r--core/java/android/hardware/input/InputDeviceIdentifier.aidl19
-rw-r--r--core/java/android/hardware/input/InputDeviceIdentifier.java82
-rw-r--r--core/java/android/hardware/input/InputManager.java84
-rw-r--r--core/java/android/hardware/input/InputManagerInternal.java42
-rw-r--r--core/java/android/net/ConnectivityManager.java19
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/MobileDataStateTracker.java11
-rw-r--r--core/java/android/net/ProxyDataTracker.java204
-rw-r--r--core/java/android/net/VpnService.java7
-rw-r--r--core/java/android/net/nsd/NsdServiceInfo.java188
-rw-r--r--core/java/android/os/AsyncTask.java2
-rw-r--r--core/java/android/os/Build.java7
-rw-r--r--core/java/android/os/FactoryTest.java14
-rw-r--r--core/java/android/os/INetworkManagementService.aidl2
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/PowerManager.java72
-rw-r--r--core/java/android/os/PowerManagerInternal.java60
-rw-r--r--core/java/android/os/Process.java13
-rw-r--r--core/java/android/os/RecoverySystem.java40
-rw-r--r--core/java/android/os/StrictMode.java11
-rw-r--r--core/java/android/os/Vibrator.java4
-rw-r--r--core/java/android/preference/PreferenceActivity.java7
-rw-r--r--core/java/android/print/PrinterCapabilitiesInfo.java6
-rw-r--r--core/java/android/provider/ContactsContract.java15
-rw-r--r--core/java/android/provider/DocumentsContract.java2
-rw-r--r--core/java/android/provider/MediaStore.java20
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/service/dreams/DozeHardware.java77
-rw-r--r--core/java/android/service/dreams/DreamManagerInternal.java39
-rw-r--r--core/java/android/service/dreams/DreamService.java326
-rw-r--r--core/java/android/service/dreams/IDozeHardware.aidl24
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl6
-rw-r--r--core/java/android/service/dreams/IDreamService.aidl2
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl1
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java61
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java18
-rw-r--r--core/java/android/speech/SpeechRecognizer.java2
-rw-r--r--core/java/android/text/StaticLayout.java2
-rw-r--r--core/java/android/text/format/Time.java2
-rw-r--r--core/java/android/util/LongSparseArray.java2
-rw-r--r--core/java/android/util/LongSparseLongArray.java2
-rw-r--r--core/java/android/util/SparseArray.java2
-rw-r--r--core/java/android/util/SparseBooleanArray.java2
-rw-r--r--core/java/android/util/SparseIntArray.java2
-rw-r--r--core/java/android/util/SparseLongArray.java2
-rw-r--r--core/java/android/util/TypedValue.java16
-rw-r--r--core/java/android/view/Display.java62
-rw-r--r--core/java/android/view/DisplayInfo.java13
-rw-r--r--core/java/android/view/IWindow.aidl1
-rw-r--r--core/java/android/view/InputDevice.java102
-rw-r--r--core/java/android/view/KeyEvent.java47
-rw-r--r--core/java/android/view/MenuInflater.java36
-rw-r--r--core/java/android/view/MotionEvent.java8
-rw-r--r--core/java/android/view/SurfaceControl.java72
-rw-r--r--core/java/android/view/View.java211
-rw-r--r--core/java/android/view/ViewConfiguration.java39
-rw-r--r--core/java/android/view/ViewGroup.java25
-rw-r--r--core/java/android/view/ViewRootImpl.java195
-rw-r--r--core/java/android/view/VolumePanel.java1
-rw-r--r--core/java/android/view/Window.java13
-rw-r--r--core/java/android/view/WindowInsets.java304
-rw-r--r--core/java/android/view/WindowManager.java10
-rw-r--r--core/java/android/view/WindowManagerInternal.java33
-rw-r--r--core/java/android/view/WindowManagerPolicy.java28
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java40
-rw-r--r--core/java/android/webkit/WebView.java9
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java5
-rw-r--r--core/java/android/widget/AbsListView.java184
-rw-r--r--core/java/android/widget/CalendarView.java53
-rw-r--r--core/java/android/widget/FastScroller.java30
-rw-r--r--core/java/android/widget/Gallery.java2
-rw-r--r--core/java/android/widget/ImageView.java2
-rw-r--r--core/java/android/widget/ListPopupWindow.java4
-rw-r--r--core/java/android/widget/NumberPicker.java53
-rw-r--r--core/java/android/widget/PopupWindow.java2
-rw-r--r--core/java/android/widget/ProgressBar.java5
-rw-r--r--core/java/android/widget/ShareActionProvider.java8
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java15
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java10
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java9
-rw-r--r--core/java/com/android/internal/os/BinderInternal.java7
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java6
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/java/com/android/internal/view/RotationPolicy.java6
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java36
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuPresenter.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuBuilder.java27
-rw-r--r--core/java/com/android/internal/widget/ActionBarOverlayLayout.java20
-rw-r--r--core/java/com/android/internal/widget/SwipeDismissLayout.java308
-rw-r--r--core/java/com/android/server/LocalServices.java60
-rw-r--r--core/java/com/android/server/SystemService.java218
-rw-r--r--core/java/com/android/server/SystemServiceManager.java164
162 files changed, 6823 insertions, 1461 deletions
diff --git a/core/java/android/annotation/PrivateApi.java b/core/java/android/annotation/PrivateApi.java
new file mode 100644
index 0000000..985eafe
--- /dev/null
+++ b/core/java/android/annotation/PrivateApi.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Indicates an API is exposed for use by bundled applications.
+ * <p>
+ * These APIs are not guaranteed to remain consistent release-to-release,
+ * and are not for use by apps linking against the SDK.
+ * @hide
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface PrivateApi {
+}
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/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
new file mode 100644
index 0000000..5262a5f
--- /dev/null
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -0,0 +1,28 @@
+/*
+ * 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.app;
+
+/**
+ * Activity manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class ActivityManagerInternal {
+ // Called by the power manager.
+ public abstract void goingToSleep();
+ public abstract void wakingUp();
+}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 74266cc..14c495f 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);
@@ -1209,20 +1199,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
- case GOING_TO_SLEEP_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- goingToSleep();
- reply.writeNoException();
- return true;
- }
-
- case WAKING_UP_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- wakingUp();
- reply.writeNoException();
- return true;
- }
-
case SET_LOCK_SCREEN_SHOWN_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
setLockScreenShown(data.readInt() != 0);
@@ -1293,17 +1269,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
- case START_RUNNING_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- String pkg = data.readString();
- String cls = data.readString();
- String action = data.readString();
- String indata = data.readString();
- startRunning(pkg, cls, action, indata);
- reply.writeNoException();
- return true;
- }
-
case HANDLE_APPLICATION_CRASH_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder app = data.readStrongBinder();
@@ -2028,6 +1993,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.Stub.asInterface(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 +2728,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 +2742,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();
@@ -3566,26 +3561,6 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return pfd;
}
- public void goingToSleep() throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(GOING_TO_SLEEP_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
- public void wakingUp() throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(WAKING_UP_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public void setLockScreenShown(boolean shown) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -3673,20 +3648,6 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
- public void startRunning(String pkg, String cls, String action,
- String indata) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeString(pkg);
- data.writeString(cls);
- data.writeString(action);
- data.writeString(indata);
- mRemote.transact(START_RUNNING_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public boolean testIsSystemReady()
{
/* this base class version is never called */
@@ -4660,5 +4621,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(callback == null ? null : callback.asBinder());
+ 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 b103e71..7f8dbba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -157,7 +157,7 @@ public final class ActivityThread {
private static final int LOG_ON_PAUSE_CALLED = 30021;
private static final int LOG_ON_RESUME_CALLED = 30022;
- static ContextImpl mSystemContext = null;
+ private ContextImpl mSystemContext;
static IPackageManager sPackageManager;
@@ -1700,7 +1700,7 @@ public final class ActivityThread {
? mBoundApplication.processName : null)
+ ")");
packageInfo =
- new LoadedApk(this, aInfo, compatInfo, this, baseLoader,
+ new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
if (includeCode) {
@@ -1753,26 +1753,15 @@ public final class ActivityThread {
public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
- ContextImpl context =
- ContextImpl.createSystemContext(this);
- LoadedApk info = new LoadedApk(this, "android", context, null,
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
- context.init(info, null, this);
- context.getResources().updateConfiguration(mResourcesManager.getConfiguration(),
- mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
- mSystemContext = context;
- //Slog.i(TAG, "Created system resources " + context.getResources()
- // + ": " + context.getResources().getConfiguration());
+ mSystemContext = ContextImpl.createSystemContext(this);
}
+ return mSystemContext;
}
- return mSystemContext;
}
public void installSystemApplicationInfo(ApplicationInfo info) {
synchronized (this) {
- ContextImpl context = getSystemContext();
- context.init(new LoadedApk(this, "android", context, info,
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this);
+ getSystemContext().installSystemApplicationInfo(info);
// give ourselves a default profiler
mProfiler = new Profiler();
@@ -2258,18 +2247,29 @@ public final class ActivityThread {
private Context createBaseContextForActivity(ActivityClientRecord r,
final Activity activity) {
- ContextImpl appContext = new ContextImpl();
- appContext.init(r.packageInfo, r.token, this);
+ ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
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);
@@ -2544,8 +2544,7 @@ public final class ActivityThread {
agent = (BackupAgent) cl.loadClass(classname).newInstance();
// set up the agent's context
- ContextImpl context = new ContextImpl();
- context.init(packageInfo, null, this);
+ ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(agent);
agent.attach(context);
@@ -2617,11 +2616,10 @@ public final class ActivityThread {
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
- ContextImpl context = new ContextImpl();
- context.init(packageInfo, null, this);
+ ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
+ context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
- context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
@@ -4217,8 +4215,7 @@ public final class ActivityThread {
}
updateDefaultDensity();
- final ContextImpl appContext = new ContextImpl();
- appContext.init(data.info, null, this);
+ final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
if (!Process.isIsolated()) {
final File cacheDir = appContext.getCacheDir();
@@ -4334,8 +4331,7 @@ public final class ActivityThread {
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true);
- ContextImpl instrContext = new ContextImpl();
- instrContext.init(pi, null, this);
+ ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
java.lang.ClassLoader cl = instrContext.getClassLoader();
@@ -4950,8 +4946,8 @@ public final class ActivityThread {
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
- ContextImpl context = new ContextImpl();
- context.init(getSystemContext().mPackageInfo, null, this);
+ ContextImpl context = ContextImpl.createAppContext(
+ this, getSystemContext().mPackageInfo);
Application app = Instrumentation.newApplication(Application.class, context);
mAllApplications.add(app);
mInitialApplication = app;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
new file mode 100644
index 0000000..edf21dd
--- /dev/null
+++ b/core/java/android/app/ActivityView.java
@@ -0,0 +1,368 @@
+/*
+ * 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.ViewGroup;
+import android.view.WindowManager;
+import dalvik.system.CloseGuard;
+
+import java.lang.ref.WeakReference;
+
+/** @hide */
+public class ActivityView extends ViewGroup {
+ private static final String TAG = "ActivityView";
+ private static final boolean DEBUG = false;
+
+ DisplayMetrics mMetrics;
+ private final TextureView mTextureView;
+ private ActivityContainerWrapper 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.");
+ }
+
+ try {
+ mActivityContainer = new ActivityContainerWrapper(
+ ActivityManagerNative.getDefault().createActivityContainer(
+ mActivity.getActivityToken(), new ActivityContainerCallback(this)));
+ } catch (RemoteException e) {
+ throw new RuntimeException("ActivityView: Unable to create ActivityContainer. "
+ + e);
+ }
+
+ mTextureView = new TextureView(context);
+ mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
+ addView(mTextureView);
+
+ WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
+ mMetrics = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(mMetrics);
+
+ 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);
+ }
+
+ private boolean injectInputEvent(InputEvent event) {
+ return mActivityContainer != null && mActivityContainer.injectEvent(event);
+ }
+
+ @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);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ if (DEBUG) Log.v(TAG, "onAttachedToWindow(): mActivityContainer=" + mActivityContainer +
+ " mSurface=" + mSurface);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer +
+ " mSurface=" + mSurface);
+ }
+
+ public boolean isAttachedToDisplay() {
+ return mSurface != null;
+ }
+
+ public void startActivity(Intent intent) {
+ if (mActivityContainer == null) {
+ throw new IllegalStateException("Attempt to call startActivity after release");
+ }
+ if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " +
+ (isAttachedToDisplay() ? "" : "not") + " attached");
+ if (mSurface != null) {
+ mActivityContainer.startActivity(intent);
+ } else {
+ mQueuedIntent = intent;
+ mQueuedPendingIntent = null;
+ }
+ }
+
+ public void startActivity(IntentSender intentSender) {
+ if (mActivityContainer == null) {
+ throw new IllegalStateException("Attempt to call startActivity after release");
+ }
+ if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " +
+ (isAttachedToDisplay() ? "" : "not") + " attached");
+ final IIntentSender iIntentSender = intentSender.getTarget();
+ if (mSurface != null) {
+ mActivityContainer.startActivityIntentSender(iIntentSender);
+ } else {
+ mQueuedPendingIntent = iIntentSender;
+ mQueuedIntent = null;
+ }
+ }
+
+ public void startActivity(PendingIntent pendingIntent) {
+ if (mActivityContainer == null) {
+ throw new IllegalStateException("Attempt to call startActivity after release");
+ }
+ if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " "
+ + (isAttachedToDisplay() ? "" : "not") + " attached");
+ final IIntentSender iIntentSender = pendingIntent.getTarget();
+ if (mSurface != null) {
+ mActivityContainer.startActivityIntentSender(iIntentSender);
+ } else {
+ mQueuedPendingIntent = iIntentSender;
+ mQueuedIntent = null;
+ }
+ }
+
+ public void release() {
+ if (DEBUG) Log.v(TAG, "release() mActivityContainer=" + mActivityContainer +
+ " mSurface=" + mSurface);
+ if (mActivityContainer == null) {
+ Log.e(TAG, "Duplicate call to release");
+ return;
+ }
+ mActivityContainer.release();
+ mActivityContainer = null;
+
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+
+ mTextureView.setSurfaceTextureListener(null);
+ }
+
+ private void attachToSurfaceWhenReady() {
+ final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
+ if (surfaceTexture == null || mSurface != null) {
+ // Either not ready to attach, or already attached.
+ return;
+ }
+
+ mSurface = new Surface(surfaceTexture);
+ try {
+ mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
+ } catch (RemoteException e) {
+ mSurface.release();
+ mSurface = null;
+ throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
+ }
+
+ if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null ||
+ mQueuedPendingIntent != null ? "" : "no") + " queued intent");
+ if (mQueuedIntent != null) {
+ mActivityContainer.startActivity(mQueuedIntent);
+ mQueuedIntent = null;
+ } else if (mQueuedPendingIntent != null) {
+ mActivityContainer.startActivityIntentSender(mQueuedPendingIntent);
+ mQueuedPendingIntent = null;
+ }
+ }
+
+ private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
+ int height) {
+ if (mActivityContainer == null) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height="
+ + height);
+ mWidth = width;
+ mHeight = height;
+ attachToSurfaceWhenReady();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
+ int height) {
+ if (mActivityContainer == null) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ if (mActivityContainer == null) {
+ return true;
+ }
+ if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed");
+ mSurface.release();
+ mSurface = null;
+ try {
+ mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to set surface of ActivityContainer. " + e);
+ }
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+// Log.d(TAG, "onSurfaceTextureUpdated");
+ }
+
+ }
+
+ private static class ActivityContainerCallback extends IActivityContainerCallback.Stub {
+ private final WeakReference<ActivityView> mActivityViewWeakReference;
+
+ ActivityContainerCallback(ActivityView activityView) {
+ mActivityViewWeakReference = new WeakReference<ActivityView>(activityView);
+ }
+
+ @Override
+ public void setVisible(IBinder container, boolean visible) {
+ if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible +
+ " ActivityView=" + mActivityViewWeakReference.get());
+ }
+ }
+
+ private static class ActivityContainerWrapper {
+ private final IActivityContainer mIActivityContainer;
+ private final CloseGuard mGuard = CloseGuard.get();
+
+ ActivityContainerWrapper(IActivityContainer container) {
+ mIActivityContainer = container;
+ mGuard.open("release");
+ }
+
+ void attachToDisplay(int displayId) {
+ try {
+ mIActivityContainer.attachToDisplay(displayId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ void setSurface(Surface surface, int width, int height, int density)
+ throws RemoteException {
+ mIActivityContainer.setSurface(surface, width, height, density);
+ }
+
+ int startActivity(Intent intent) {
+ try {
+ return mIActivityContainer.startActivity(intent);
+ } catch (RemoteException e) {
+ throw new RuntimeException("ActivityView: Unable to startActivity. " + e);
+ }
+ }
+
+ int startActivityIntentSender(IIntentSender intentSender) {
+ try {
+ return mIActivityContainer.startActivityIntentSender(intentSender);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to startActivity from IntentSender. " + e);
+ }
+ }
+
+ int getDisplayId() {
+ try {
+ return mIActivityContainer.getDisplayId();
+ } catch (RemoteException e) {
+ return -1;
+ }
+ }
+
+ boolean injectEvent(InputEvent event) {
+ try {
+ return mIActivityContainer.injectEvent(event);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ void release() {
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+ try {
+ mIActivityContainer.release();
+ mGuard.close();
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: finalize called");
+ try {
+ if (mGuard != null) {
+ mGuard.warnIfOpen();
+ release();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ }
+}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index aece462..079cf7a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -36,7 +36,7 @@ import android.os.RemoteException;
* API for interacting with "application operation" tracking.
*
* <p>This API is not generally intended for third party application developers; most
- * features are only available to system applicatins. Obtain an instance of it through
+ * features are only available to system applications. Obtain an instance of it through
* {@link Context#getSystemService(String) Context.getSystemService} with
* {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p>
*/
@@ -878,7 +878,7 @@ public class AppOpsManager {
}
/**
- * Like {@link #checkOp but instead of throwing a {@link SecurityException} it
+ * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
* returns {@link #MODE_ERRORED}.
*/
public int checkOpNoThrow(String op, int uid, String packageName) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a280448..c5e6ac4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -129,6 +129,24 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
+ public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+ // Try to find a main leanback_launcher activity.
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+ intentToResolve.setPackage(packageName);
+ List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
+
+ if (ris == null || ris.size() <= 0) {
+ return null;
+ }
+ Intent intent = new Intent(intentToResolve);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setClassName(ris.get(0).activityInfo.packageName,
+ ris.get(0).activityInfo.name);
+ return intent;
+ }
+
+ @Override
public int[] getPackageGids(String packageName)
throws NameNotFoundException {
try {
@@ -729,6 +747,39 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
+ public Drawable getActivityBanner(ComponentName activityName)
+ throws NameNotFoundException {
+ return getActivityInfo(activityName, 0).loadBanner(this);
+ }
+
+ @Override
+ public Drawable getActivityBanner(Intent intent)
+ throws NameNotFoundException {
+ if (intent.getComponent() != null) {
+ return getActivityBanner(intent.getComponent());
+ }
+
+ ResolveInfo info = resolveActivity(
+ intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (info != null) {
+ return info.activityInfo.loadBanner(this);
+ }
+
+ throw new NameNotFoundException(intent.toUri(0));
+ }
+
+ @Override
+ public Drawable getApplicationBanner(ApplicationInfo info) {
+ return info.loadBanner(this);
+ }
+
+ @Override
+ public Drawable getApplicationBanner(String packageName)
+ throws NameNotFoundException {
+ return getApplicationBanner(getApplicationInfo(packageName, 0));
+ }
+
+ @Override
public Drawable getActivityLogo(ComponentName activityName)
throws NameNotFoundException {
return getActivityInfo(activityName, 0).loadLogo(this);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8d127c6..924d656 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -51,6 +51,8 @@ import android.hardware.ConsumerIrManager;
import android.hardware.ISerialManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
+import android.hardware.hdmi.HdmiCecManager;
+import android.hardware.hdmi.IHdmiCecService;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
import android.hardware.input.InputManager;
@@ -183,22 +185,31 @@ class ContextImpl extends Context {
*/
private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;
- /*package*/ LoadedApk mPackageInfo;
- private String mBasePackageName;
- private String mOpPackageName;
- private Resources mResources;
- /*package*/ ActivityThread mMainThread;
+ final ActivityThread mMainThread;
+ final LoadedApk mPackageInfo;
+
+ private final IBinder mActivityToken;
+
+ private final UserHandle mUser;
+
+ private final ApplicationContentResolver mContentResolver;
+
+ private final String mBasePackageName;
+ private final String mOpPackageName;
+
+ private final ResourcesManager mResourcesManager;
+ private final Resources mResources;
+ private final Display mDisplay; // may be null if default display
+ private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+ private final Configuration mOverrideConfiguration;
+
+ private final boolean mRestricted;
+
private Context mOuterContext;
- private IBinder mActivityToken = null;
- private ApplicationContentResolver mContentResolver;
private int mThemeResource = 0;
private Resources.Theme mTheme = null;
private PackageManager mPackageManager;
- private Display mDisplay; // may be null if default display
private Context mReceiverRestrictedContext = null;
- private boolean mRestricted;
- private UserHandle mUser;
- private ResourcesManager mResourcesManager;
private final Object mSync = new Object();
@@ -220,8 +231,6 @@ class ContextImpl extends Context {
private static final String[] EMPTY_FILE_LIST = {};
- final private DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
-
/**
* Override this class when the system service constructor needs a
* ContextImpl. Else, use StaticServiceFetcher below.
@@ -350,16 +359,24 @@ class ContextImpl extends Context {
return new BluetoothManager(ctx);
}});
+ registerService(HDMI_CEC_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(HDMI_CEC_SERVICE);
+ return new HdmiCecManager(IHdmiCecService.Stub.asInterface(b));
+ }});
+
+
registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new ClipboardManager(ctx.getOuterContext(),
ctx.mMainThread.getHandler());
}});
- registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
+ registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
- return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+ return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b),
+ ctx.getPackageName());
}});
registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
@@ -1878,20 +1895,17 @@ class ContextImpl extends Context {
@Override
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
throws NameNotFoundException {
+ final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
if (packageName.equals("system") || packageName.equals("android")) {
- final ContextImpl context = new ContextImpl(mMainThread.getSystemContext());
- context.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
- context.init(mPackageInfo, null, mMainThread, mResources, mBasePackageName, user);
- return context;
+ return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
+ user, restricted, mDisplay, mOverrideConfiguration);
}
- LoadedApk pi =
- mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags,
- user.getIdentifier());
+ LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
+ flags, user.getIdentifier());
if (pi != null) {
- ContextImpl c = new ContextImpl();
- c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
- c.init(pi, null, mMainThread, mResources, mBasePackageName, user);
+ ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
+ user, restricted, mDisplay, mOverrideConfiguration);
if (c.mResources != null) {
return c;
}
@@ -1899,7 +1913,7 @@ class ContextImpl extends Context {
// Should be a better exception.
throw new PackageManager.NameNotFoundException(
- "Application package " + packageName + " not found");
+ "Application package " + packageName + " not found");
}
@Override
@@ -1908,12 +1922,8 @@ class ContextImpl extends Context {
throw new IllegalArgumentException("overrideConfiguration must not be null");
}
- ContextImpl c = new ContextImpl();
- c.init(mPackageInfo, null, mMainThread);
- c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
- mPackageInfo.getOverlayDirs(), getDisplayId(), overrideConfiguration,
- mResources.getCompatibilityInfo(), mActivityToken);
- return c;
+ return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
+ mUser, mRestricted, mDisplay, overrideConfiguration);
}
@Override
@@ -1922,15 +1932,8 @@ class ContextImpl extends Context {
throw new IllegalArgumentException("display must not be null");
}
- int displayId = display.getDisplayId();
-
- ContextImpl context = new ContextImpl();
- context.init(mPackageInfo, null, mMainThread);
- context.mDisplay = display;
- DisplayAdjustments daj = getDisplayAdjustments(displayId);
- context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
- mPackageInfo.getOverlayDirs(), displayId, null, daj.getCompatibilityInfo(), null);
- return context;
+ return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
+ mUser, mRestricted, display, mOverrideConfiguration);
}
private int getDisplayId() {
@@ -1972,43 +1975,76 @@ class ContextImpl extends Context {
}
static ContextImpl createSystemContext(ActivityThread mainThread) {
- final ContextImpl context = new ContextImpl();
- context.init(Resources.getSystem(), mainThread, Process.myUserHandle());
+ LoadedApk packageInfo = new LoadedApk(mainThread);
+ ContextImpl context = new ContextImpl(null, mainThread,
+ packageInfo, null, null, false, null, null);
+ context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
+ context.mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
return context;
}
- ContextImpl() {
- mOuterContext = this;
+ static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
+ if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
+ return new ContextImpl(null, mainThread,
+ packageInfo, null, null, false, null, null);
}
- /**
- * Create a new ApplicationContext from an existing one. The new one
- * works and operates the same as the one it is copying.
- *
- * @param context Existing application context.
- */
- public ContextImpl(ContextImpl context) {
- mPackageInfo = context.mPackageInfo;
- mBasePackageName = context.mBasePackageName;
- mOpPackageName = context.mOpPackageName;
- mResources = context.mResources;
- mMainThread = context.mMainThread;
- mContentResolver = context.mContentResolver;
- mUser = context.mUser;
- mDisplay = context.mDisplay;
- mOuterContext = this;
- mDisplayAdjustments.setCompatibilityInfo(mPackageInfo.getCompatibilityInfo());
+ static ContextImpl createActivityContext(ActivityThread mainThread,
+ LoadedApk packageInfo, IBinder activityToken) {
+ if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
+ if (activityToken == null) throw new IllegalArgumentException("activityInfo");
+ return new ContextImpl(null, mainThread,
+ packageInfo, activityToken, null, false, null, null);
}
- final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) {
- init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle());
- }
+ private ContextImpl(ContextImpl container, ActivityThread mainThread,
+ LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
+ Display display, Configuration overrideConfiguration) {
+ mOuterContext = this;
+
+ mMainThread = mainThread;
+ mActivityToken = activityToken;
+ mRestricted = restricted;
+
+ if (user == null) {
+ user = Process.myUserHandle();
+ }
+ mUser = user;
- final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,
- Resources container, String basePackageName, UserHandle user) {
mPackageInfo = packageInfo;
- if (basePackageName != null) {
- mBasePackageName = mOpPackageName = basePackageName;
+ mContentResolver = new ApplicationContentResolver(this, mainThread, user);
+ mResourcesManager = ResourcesManager.getInstance();
+ mDisplay = display;
+ mOverrideConfiguration = overrideConfiguration;
+
+ final int displayId = getDisplayId();
+ CompatibilityInfo compatInfo = null;
+ if (container != null) {
+ compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
+ }
+ if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) {
+ compatInfo = packageInfo.getCompatibilityInfo();
+ }
+ mDisplayAdjustments.setCompatibilityInfo(compatInfo);
+ mDisplayAdjustments.setActivityToken(activityToken);
+
+ Resources resources = packageInfo.getResources(mainThread);
+ if (resources != null) {
+ if (activityToken != null
+ || displayId != Display.DEFAULT_DISPLAY
+ || overrideConfiguration != null
+ || (compatInfo != null && compatInfo.applicationScale
+ != resources.getCompatibilityInfo().applicationScale)) {
+ resources = mResourcesManager.getTopLevelResources(
+ packageInfo.getResDir(), packageInfo.getOverlayDirs(), displayId,
+ overrideConfiguration, compatInfo, activityToken);
+ }
+ }
+ mResources = resources;
+
+ if (container != null) {
+ mBasePackageName = container.mBasePackageName;
+ mOpPackageName = container.mOpPackageName;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
@@ -2022,45 +2058,10 @@ class ContextImpl extends Context {
mOpPackageName = mBasePackageName;
}
}
- mResources = mPackageInfo.getResources(mainThread);
- mResourcesManager = ResourcesManager.getInstance();
-
- CompatibilityInfo compatInfo =
- container == null ? null : container.getCompatibilityInfo();
- if (mResources != null &&
- ((compatInfo != null && compatInfo.applicationScale !=
- mResources.getCompatibilityInfo().applicationScale)
- || activityToken != null)) {
- if (DEBUG) {
- Log.d(TAG, "loaded context has different scaling. Using container's" +
- " compatiblity info:" + container.getDisplayMetrics());
- }
- if (compatInfo == null) {
- compatInfo = packageInfo.getCompatibilityInfo();
- }
- mDisplayAdjustments.setCompatibilityInfo(compatInfo);
- mDisplayAdjustments.setActivityToken(activityToken);
- mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
- mPackageInfo.getOverlayDirs(), Display.DEFAULT_DISPLAY, null, compatInfo,
- activityToken);
- } else {
- mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
- mDisplayAdjustments.setActivityToken(activityToken);
- }
- mMainThread = mainThread;
- mActivityToken = activityToken;
- mContentResolver = new ApplicationContentResolver(this, mainThread, user);
- mUser = user;
}
- final void init(Resources resources, ActivityThread mainThread, UserHandle user) {
- mPackageInfo = null;
- mBasePackageName = null;
- mOpPackageName = null;
- mResources = resources;
- mMainThread = mainThread;
- mContentResolver = new ApplicationContentResolver(this, mainThread, user);
- mUser = user;
+ void installSystemApplicationInfo(ApplicationInfo info) {
+ mPackageInfo.installSystemApplicationInfo(info);
}
final void scheduleFinalCleanup(String who, String what) {
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..cc3b10c
--- /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 setSurface(in Surface surface, int width, int height, int density);
+ int startActivity(in Intent intent);
+ int startActivityIntentSender(in IIntentSender intentSender);
+ int getDisplayId();
+ boolean injectEvent(in InputEvent event);
+ void release();
+}
diff --git a/core/java/android/app/IActivityContainerCallback.aidl b/core/java/android/app/IActivityContainerCallback.aidl
new file mode 100644
index 0000000..7f6d2c3
--- /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 setVisible(IBinder container, boolean visible);
+}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 77c2ea0..4e2a57d 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 */
@@ -229,8 +228,6 @@ public interface IActivityManager extends IInterface {
public void forceStopPackage(final String packageName, int userId) throws RemoteException;
// Note: probably don't want to allow applications access to these.
- public void goingToSleep() throws RemoteException;
- public void wakingUp() throws RemoteException;
public void setLockScreenShown(boolean shown) throws RemoteException;
public void unhandledBack() throws RemoteException;
@@ -250,8 +247,6 @@ public interface IActivityManager extends IInterface {
public boolean killProcessesBelowForeground(String reason) throws RemoteException;
// Special low-level communication with activity manager.
- public void startRunning(String pkg, String cls, String action,
- String data) throws RemoteException;
public void handleApplicationCrash(IBinder app,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
public boolean handleApplicationWtf(IBinder app, String tag,
@@ -408,6 +403,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
*/
@@ -514,7 +521,6 @@ public interface IActivityManager extends IInterface {
// Please keep these transaction codes the same -- they are also
// sent by C++ code.
- int START_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
int HANDLE_APPLICATION_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
int START_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
int UNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
@@ -550,8 +556,6 @@ public interface IActivityManager extends IInterface {
int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
int ACTIVITY_RESUMED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
- int GOING_TO_SLEEP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
- int WAKING_UP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
int SET_ALWAYS_FINISH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
int START_INSTRUMENTATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
@@ -678,12 +682,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 +698,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/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9f933ca..9911467 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -45,7 +45,8 @@ interface INotificationManager
void unregisterListener(in INotificationListener listener, int userid);
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
- void cancelAllNotificationsFromListener(in INotificationListener token);
+ void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
- StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token);
+ StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+ String[] getActiveNotificationKeysFromListener(in INotificationListener token);
} \ No newline at end of file
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/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0115d1b..d409352 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -72,7 +72,7 @@ public final class LoadedApk {
private static final String TAG = "LoadedApk";
private final ActivityThread mActivityThread;
- private final ApplicationInfo mApplicationInfo;
+ private ApplicationInfo mApplicationInfo;
final String mPackageName;
private final String mAppDir;
private final String mResDir;
@@ -111,8 +111,7 @@ public final class LoadedApk {
* so MUST NOT call back out to the activity manager.
*/
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
- CompatibilityInfo compatInfo,
- ActivityThread mainThread, ClassLoader baseLoader,
+ CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode) {
mActivityThread = activityThread;
mApplicationInfo = aInfo;
@@ -134,31 +133,17 @@ public final class LoadedApk {
mSecurityViolation = securityViolation;
mIncludeCode = includeCode;
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
-
- if (mAppDir == null) {
- if (ActivityThread.mSystemContext == null) {
- ActivityThread.mSystemContext =
- ContextImpl.createSystemContext(mainThread);
- ResourcesManager resourcesManager = ResourcesManager.getInstance();
- ActivityThread.mSystemContext.getResources().updateConfiguration(
- resourcesManager.getConfiguration(),
- resourcesManager.getDisplayMetricsLocked(
- Display.DEFAULT_DISPLAY, mDisplayAdjustments), compatInfo);
- //Slog.i(TAG, "Created system resources "
- // + mSystemContext.getResources() + ": "
- // + mSystemContext.getResources().getConfiguration());
- }
- mClassLoader = ActivityThread.mSystemContext.getClassLoader();
- mResources = ActivityThread.mSystemContext.getResources();
- }
}
- public LoadedApk(ActivityThread activityThread, String name,
- Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {
+ /**
+ * Create information about the system package.
+ * Must call {@link #installSystemApplicationInfo} later.
+ */
+ LoadedApk(ActivityThread activityThread) {
mActivityThread = activityThread;
- mApplicationInfo = info != null ? info : new ApplicationInfo();
- mApplicationInfo.packageName = name;
- mPackageName = name;
+ mApplicationInfo = new ApplicationInfo();
+ mApplicationInfo.packageName = "android";
+ mPackageName = "android";
mAppDir = null;
mResDir = null;
mOverlayDirs = null;
@@ -169,9 +154,16 @@ public final class LoadedApk {
mBaseClassLoader = null;
mSecurityViolation = false;
mIncludeCode = true;
- mClassLoader = systemContext.getClassLoader();
- mResources = systemContext.getResources();
- mDisplayAdjustments.setCompatibilityInfo(compatInfo);
+ mClassLoader = ClassLoader.getSystemClassLoader();
+ mResources = Resources.getSystem();
+ }
+
+ /**
+ * Sets application info about the system package.
+ */
+ void installSystemApplicationInfo(ApplicationInfo info) {
+ assert info.packageName.equals("android");
+ mApplicationInfo = info;
}
public String getPackageName() {
@@ -513,8 +505,7 @@ public final class LoadedApk {
try {
java.lang.ClassLoader cl = getClassLoader();
- ContextImpl appContext = new ContextImpl();
- appContext.init(this, null, mActivityThread);
+ ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c63e586..e6b5de1 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;
/**
@@ -394,41 +401,82 @@ public class Notification implements Parcelable
public int priority;
/**
- * @hide
- * Notification type: incoming call (voice or video) or similar synchronous communication request.
+ * Notification category: incoming call (voice or video) or similar synchronous communication request.
*/
- public static final String KIND_CALL = "android.call";
+ public static final String CATEGORY_CALL = "call";
/**
- * @hide
- * Notification type: incoming direct message (SMS, instant message, etc.).
+ * Notification category: incoming direct message (SMS, instant message, etc.).
*/
- public static final String KIND_MESSAGE = "android.message";
+ public static final String CATEGORY_MESSAGE = "msg";
/**
- * @hide
- * Notification type: asynchronous bulk message (email).
+ * Notification category: asynchronous bulk message (email).
*/
- public static final String KIND_EMAIL = "android.email";
+ public static final String CATEGORY_EMAIL = "email";
/**
- * @hide
- * Notification type: calendar event.
+ * Notification category: calendar event.
*/
- public static final String KIND_EVENT = "android.event";
+ public static final String CATEGORY_EVENT = "event";
/**
- * @hide
- * Notification type: promotion or advertisement.
+ * Notification category: promotion or advertisement.
*/
- public static final String KIND_PROMO = "android.promo";
+ public static final String CATEGORY_PROMO = "promo";
/**
- * @hide
- * If this notification matches of one or more special types (see the <code>KIND_*</code>
- * constants), add them here, best match first.
+ * Notification category: alarm or timer.
+ */
+ public static final String CATEGORY_ALARM = "alarm";
+
+ /**
+ * Notification category: progress of a long-running background operation.
+ */
+ public static final String CATEGORY_PROGRESS = "progress";
+
+ /**
+ * Notification category: social network or sharing update.
+ */
+ public static final String CATEGORY_SOCIAL = "social";
+
+ /**
+ * Notification category: error in background operation or authentication status.
+ */
+ public static final String CATEGORY_ERROR = "err";
+
+ /**
+ * Notification category: media transport control for playback.
+ */
+ public static final String CATEGORY_TRANSPORT = "transport";
+
+ /**
+ * Notification category: system or device status update. Reserved for system use.
*/
- public String[] kind;
+ public static final String CATEGORY_SYSTEM = "sys";
+
+ /**
+ * Notification category: indication of running background service.
+ */
+ public static final String CATEGORY_SERVICE = "service";
+
+ /**
+ * Notification category: a specific, timely recommendation for a single thing.
+ * For example, a news app might want to recommend a news story it believes the user will
+ * want to read next.
+ */
+ public static final String CATEGORY_RECOMMENDATION = "recommendation";
+
+ /**
+ * Notification category: ongoing information about device or contextual status.
+ */
+ public static final String CATEGORY_STATUS = "status";
+
+ /**
+ * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
+ * that best describes this Notification. May be used by the system for ranking and filtering.
+ */
+ public String category;
/**
* Additional semantic data to be carried around with this Notification.
@@ -561,6 +609,13 @@ public class Notification implements Parcelable
public static final String EXTRA_AS_HEADS_UP = "headsup";
/**
+ * Allow certain system-generated notifications to appear before the device is provisioned.
+ * Only available to notifications coming from the android package.
+ * @hide
+ */
+ public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
+
+ /**
* Value for {@link #EXTRA_AS_HEADS_UP}.
* @hide
*/
@@ -750,7 +805,7 @@ public class Notification implements Parcelable
priority = parcel.readInt();
- kind = parcel.createStringArray(); // may set kind to null
+ category = parcel.readString();
extras = parcel.readBundle(); // may be null
@@ -815,12 +870,7 @@ public class Notification implements Parcelable
that.priority = this.priority;
- final String[] thiskind = this.kind;
- if (thiskind != null) {
- final int N = thiskind.length;
- final String[] thatkind = that.kind = new String[N];
- System.arraycopy(thiskind, 0, thatkind, 0, N);
- }
+ that.category = this.category;
if (this.extras != null) {
try {
@@ -957,7 +1007,7 @@ public class Notification implements Parcelable
parcel.writeInt(priority);
- parcel.writeStringArray(kind); // ok for null
+ parcel.writeString(category);
parcel.writeBundle(extras); // null ok
@@ -1077,16 +1127,7 @@ public class Notification implements Parcelable
sb.append(Integer.toHexString(this.defaults));
sb.append(" flags=0x");
sb.append(Integer.toHexString(this.flags));
- sb.append(" kind=[");
- if (this.kind == null) {
- sb.append("null");
- } else {
- for (int i=0; i<this.kind.length; i++) {
- if (i>0) sb.append(",");
- sb.append(this.kind[i]);
- }
- }
- sb.append("]");
+ sb.append(" category="); sb.append(this.category);
if (actions != null) {
sb.append(" ");
sb.append(actions.length);
@@ -1165,7 +1206,7 @@ public class Notification implements Parcelable
private int mProgressMax;
private int mProgress;
private boolean mProgressIndeterminate;
- private ArrayList<String> mKindList = new ArrayList<String>(1);
+ private String mCategory;
private Bundle mExtras;
private int mPriority;
private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
@@ -1532,6 +1573,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
@@ -1556,24 +1608,41 @@ public class Notification implements Parcelable
}
/**
- * @hide
+ * Set the notification category.
*
- * Add a kind (category) to this notification. Optional.
+ * @see Notification#category
+ */
+ public Builder setCategory(String category) {
+ mCategory = category;
+ return this;
+ }
+
+ /**
+ * Merge additional metadata into this notification.
*
- * @see Notification#kind
+ * <p>Values within the Bundle will replace existing extras values in this Builder.
+ *
+ * @see Notification#extras
*/
- public Builder addKind(String k) {
- mKindList.add(k);
+ public Builder addExtras(Bundle bag) {
+ if (mExtras == null) {
+ mExtras = new Bundle(bag);
+ } else {
+ mExtras.putAll(bag);
+ }
return this;
}
/**
- * Add metadata to this notification.
+ * Set metadata for this notification.
*
- * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
+ * <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 +1651,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 +1864,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);
@@ -1819,12 +1905,7 @@ public class Notification implements Parcelable
if ((mDefaults & DEFAULT_LIGHTS) != 0) {
n.flags |= FLAG_SHOW_LIGHTS;
}
- if (mKindList.size() > 0) {
- n.kind = new String[mKindList.size()];
- mKindList.toArray(n.kind);
- } else {
- n.kind = null;
- }
+ n.category = mCategory;
n.priority = mPriority;
if (mActions.size() > 0) {
n.actions = new Action[mActions.size()];
@@ -1839,7 +1920,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 +1958,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 +1981,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..7129e9e 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 does not
+ * already exist, 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/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0c22740..c6731c9 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -166,9 +166,11 @@ public class UiModeManager {
/**
* Return the current running mode type. May be one of
* {@link Configuration#UI_MODE_TYPE_NORMAL Configuration.UI_MODE_TYPE_NORMAL},
- * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK}, or
- * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR}, or
- * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_APPLIANCE}.
+ * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK},
+ * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR},
+ * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_TELEVISION},
+ * {@link Configuration#UI_MODE_TYPE_APPLIANCE Configuration.UI_MODE_TYPE_APPLIANCE}, or
+ * {@link Configuration#UI_MODE_TYPE_WATCH Configuration.UI_MODE_TYPE_WATCH}.
*/
public int getCurrentModeType() {
if (mService != null) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index ced72f8..f291e82 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -45,9 +45,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import java.io.BufferedInputStream;
@@ -294,9 +292,8 @@ public class WallpaperManager {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
- Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ return BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, options);
- return generateBitmap(context, bm, width, height);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode file", e);
} finally {
@@ -323,8 +320,7 @@ public class WallpaperManager {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
- Bitmap bm = BitmapFactory.decodeStream(is, null, options);
- return generateBitmap(context, bm, width, height);
+ return BitmapFactory.decodeStream(is, null, options);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode stream", e);
} finally {
@@ -1029,62 +1025,4 @@ public class WallpaperManager {
public void clear() throws IOException {
setResource(com.android.internal.R.drawable.default_wallpaper);
}
-
- static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
- if (bm == null) {
- return null;
- }
-
- WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- DisplayMetrics metrics = new DisplayMetrics();
- wm.getDefaultDisplay().getMetrics(metrics);
- bm.setDensity(metrics.noncompatDensityDpi);
-
- if (width <= 0 || height <= 0
- || (bm.getWidth() == width && bm.getHeight() == height)) {
- return bm;
- }
-
- // This is the final bitmap we want to return.
- try {
- Bitmap newbm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- newbm.setDensity(metrics.noncompatDensityDpi);
-
- Canvas c = new Canvas(newbm);
- Rect targetRect = new Rect();
- targetRect.right = bm.getWidth();
- targetRect.bottom = bm.getHeight();
-
- int deltaw = width - targetRect.right;
- int deltah = height - targetRect.bottom;
-
- if (deltaw > 0 || deltah > 0) {
- // We need to scale up so it covers the entire area.
- float scale;
- if (deltaw > deltah) {
- scale = width / (float)targetRect.right;
- } else {
- scale = height / (float)targetRect.bottom;
- }
- targetRect.right = (int)(targetRect.right*scale);
- targetRect.bottom = (int)(targetRect.bottom*scale);
- deltaw = width - targetRect.right;
- deltah = height - targetRect.bottom;
- }
-
- targetRect.offset(deltaw/2, deltah/2);
-
- Paint paint = new Paint();
- paint.setFilterBitmap(true);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- c.drawBitmap(bm, null, targetRect, paint);
-
- bm.recycle();
- c.setBitmap(null);
- return newbm;
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "Can't generate default bitmap", e);
- return bm;
- }
- }
}
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..646be06 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,21 +20,23 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
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;
@@ -214,6 +216,22 @@ public final class BluetoothAdapter {
"android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
/**
+ * 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";
+
+ /**
* Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
* intents to request the current scan mode. Possible values are:
* {@link #SCAN_MODE_NONE},
@@ -251,7 +269,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.
@@ -350,9 +367,27 @@ public final class BluetoothAdapter {
/** The profile is in disconnecting state */
public static final int STATE_DISCONNECTING = 3;
+ /** States for Bluetooth LE advertising */
+ /** @hide */
+ public static final int STATE_ADVERTISE_STARTING = 0;
+ /** @hide */
+ public static final int STATE_ADVERTISE_STARTED = 1;
+ /** @hide */
+ public static final int STATE_ADVERTISE_STOPPING = 2;
+ /** @hide */
+ public static final int STATE_ADVERTISE_STOPPED = 3;
+ /**
+ * Force stopping advertising without callback in case the advertising app dies.
+ * @hide
+ */
+ public static final int STATE_ADVERTISE_FORCE_STOPPING = 4;
+
/** @hide */
public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
+ /** @hide */
+ public static final int ADVERTISE_CALLBACK_SUCCESS = 0;
+
private static final int ADDRESS_LENGTH = 17;
/**
@@ -365,6 +400,10 @@ public final class BluetoothAdapter {
private IBluetooth mService;
private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients;
+ private BluetoothAdvScanData mBluetoothAdvScanData = null;
+ private GattCallbackWrapper mAdvertisingGattCallback;
+ private final Handler mHandler; // Handler to post the advertise callback to run on main thread.
+ private final Object mLock = new Object();
/**
* Get a handle to the default local Bluetooth adapter.
@@ -400,6 +439,7 @@ public final class BluetoothAdapter {
} catch (RemoteException e) {Log.e(TAG, "", e);}
mManagerService = managerService;
mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
+ mHandler = new Handler(Looper.getMainLooper());
}
/**
@@ -438,6 +478,129 @@ public final class BluetoothAdapter {
}
/**
+ * Returns a {@link BluetoothAdvScanData} object representing advertising data.
+ * Data will be reset when bluetooth service is turned off.
+ * @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;
+ }
+ }
+
+ /**
+ * Interface for BLE advertising callback.
+ *
+ * @hide
+ */
+ public interface AdvertiseCallback {
+ /**
+ * Callback when advertise starts.
+ * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure.
+ */
+ void onAdvertiseStart(int status);
+ /**
+ * Callback when advertise stops.
+ * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure.
+ */
+ void onAdvertiseStop(int status);
+ }
+
+ /**
+ * Start BLE advertising using current {@link BluetoothAdvScanData}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}
+ *
+ * @param callback - {@link AdvertiseCallback}
+ * @return true if BLE advertising succeeds, false otherwise.
+ * @hide
+ */
+ public boolean startAdvertising(final AdvertiseCallback callback) {
+ 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 (mAdvertisingGattCallback == null || mAdvertisingGattCallback.mLeHandle == -1) {
+ Log.e(TAG, "failed to restart advertising, invalid callback");
+ return false;
+ }
+ iGatt.startAdvertising(mAdvertisingGattCallback.mLeHandle);
+ // Run the callback from main thread.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // callback with status success.
+ callback.onAdvertiseStart(ADVERTISE_CALLBACK_SUCCESS);
+ }
+ });
+ return true;
+ }
+ UUID uuid = UUID.randomUUID();
+ GattCallbackWrapper wrapper =
+ new GattCallbackWrapper(this, null, null, callback);
+ iGatt.registerClient(new ParcelUuid(uuid), wrapper);
+ if (!wrapper.advertiseStarted()) {
+ return false;
+ }
+ synchronized (mLock) {
+ mAdvertisingGattCallback = wrapper;
+ }
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ }
+
+ /**
+ * Stop BLE advertising. The callback has to be the same one used for start advertising.
+ *
+ * @param callback - {@link AdvertiseCallback}
+ * @return true if BLE advertising stops, false otherwise.
+ * @hide
+ */
+ public boolean stopAdvertising(AdvertiseCallback callback) {
+ try {
+ IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+ if (iGatt == null) {
+ // BLE is not supported
+ return false;
+ }
+ if (mAdvertisingGattCallback == null) {
+ // no callback.
+ return false;
+ }
+ // Make sure same callback is used for start and stop advertising.
+ if (callback != mAdvertisingGattCallback.mAdvertiseCallback) {
+ Log.e(TAG, "must use the same callback for star/stop advertising");
+ return false;
+ }
+ mAdvertisingGattCallback.stopAdvertising();
+ 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 +1012,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
@@ -1272,6 +1452,8 @@ public final class BluetoothAdapter {
if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
synchronized (mManagerCallback) {
mService = null;
+ // Reset bluetooth adv scan data when Gatt service is down.
+ mBluetoothAdvScanData = null;
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
try {
if (cb != null) {
@@ -1547,7 +1729,9 @@ public final class BluetoothAdapter {
private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
+ private final AdvertiseCallback mAdvertiseCallback;
private final LeScanCallback mLeScanCb;
+
// mLeHandle 0: not registered
// -1: scan stopped
// >0: registered and scan started
@@ -1561,16 +1745,34 @@ public final class BluetoothAdapter {
mLeScanCb = leScanCb;
mScanFilter = uuid;
mLeHandle = 0;
+ mAdvertiseCallback = null;
+ }
+
+ public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb,
+ UUID[] uuid, AdvertiseCallback callback) {
+ mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter);
+ mLeScanCb = leScanCb;
+ mScanFilter = uuid;
+ mLeHandle = 0;
+ mAdvertiseCallback = callback;
}
public boolean scanStarted() {
+ return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT);
+ }
+
+ public boolean advertiseStarted() {
+ // Wait for registeration callback.
+ return waitForRegisteration(1);
+ }
+
+ private boolean waitForRegisteration(int maxWaitCount) {
boolean started = false;
synchronized(this) {
if (mLeHandle == -1) return false;
-
int count = 0;
// wait for callback registration and LE scan to start
- while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) {
+ while (mLeHandle == 0 && count < maxWaitCount) {
try {
wait(LE_CALLBACK_REG_TIMEOUT);
} catch (InterruptedException e) {
@@ -1583,6 +1785,27 @@ 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();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to stop advertising" + e);
+ }
+ } else {
+ Log.e(TAG, "stopAdvertising, BluetoothAdapter is null");
+ }
+ notifyAll();
+ }
+ }
+
public void stopLeScan() {
synchronized(this) {
if (mLeHandle <= 0) {
@@ -1624,14 +1847,18 @@ public final class BluetoothAdapter {
BluetoothAdapter adapter = mBluetoothAdapter.get();
if (adapter != null) {
iGatt = adapter.getBluetoothManager().getBluetoothGatt();
- if (mScanFilter == null) {
- iGatt.startScan(mLeHandle, false);
+ if (mAdvertiseCallback != null) {
+ 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 +1869,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);
@@ -1670,7 +1897,7 @@ public final class BluetoothAdapter {
* @hide
*/
public void onScanResult(String address, int rssi, byte[] advData) {
- if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+ if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
// Check null in case the scan has been stopped
synchronized(this) {
@@ -1759,9 +1986,53 @@ public final class BluetoothAdapter {
// no op
}
- public void onListen(int status) {
+ public void onAdvertiseStateChange(int advertiseState, int status) {
+ Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status);
+ if (advertiseState == STATE_ADVERTISE_STARTED) {
+ if (status == ADVERTISE_CALLBACK_SUCCESS) {
+ mAdvertiseCallback.onAdvertiseStart(status);
+ } else {
+ // If status is unsuccessful and advertise state is started, it means stop
+ // advertising fails.
+ mAdvertiseCallback.onAdvertiseStop(status);
+ }
+ } else {
+ synchronized (this) {
+ if (status == ADVERTISE_CALLBACK_SUCCESS) {
+ BluetoothAdapter adapter = mBluetoothAdapter.get();
+ if (adapter != null) {
+ try {
+ IBluetoothGatt iGatt =
+ adapter.getBluetoothManager().getBluetoothGatt();
+ Log.d(TAG, "unregistering client " + mLeHandle);
+ iGatt.unregisterClient(mLeHandle);
+ // Reset advertise app handle.
+ mLeHandle = -1;
+ adapter.mAdvertisingGattCallback = null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to unregister client" + e);
+ }
+ } else {
+ Log.e(TAG, "cannot unregister client, BluetoothAdapter is null");
+ }
+ }
+ }
+ if (status == ADVERTISE_CALLBACK_SUCCESS) {
+ mAdvertiseCallback.onAdvertiseStop(status);
+ } else{
+ // If status is unsuccesful and advertise state is stopped, it means start
+ // advertising fails.
+ mAdvertiseCallback.onAdvertiseStart(status);
+ }
+ }
+ }
+
+ /**
+ * Callback reporting LE ATT MTU.
+ * @hide
+ */
+ public void onConfigureMTU(String address, int mtu, int status) {
// no op
}
}
-
}
diff --git a/core/java/android/bluetooth/BluetoothAdvScanData.java b/core/java/android/bluetooth/BluetoothAdvScanData.java
new file mode 100644
index 0000000..df2c256
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdvScanData.java
@@ -0,0 +1,152 @@
+/*
+ * 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) {
+ Log.e(TAG, "Unable to set manufacturer id and data.", 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) {
+ Log.e(TAG, "Unable to set service data.", 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) {
+ Log.e(TAG, "Unable to get service uuids.", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns manufacturer data.
+ */
+ public byte[] getManufacturerData() {
+ if (mBluetoothGatt == null) return null;
+ try {
+ return mBluetoothGatt.getAdvManufacturerData();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get manufacturer data.", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns service data.
+ */
+ public byte[] getServiceData() {
+ if (mBluetoothGatt == null) return null;
+ try {
+ return mBluetoothGatt.getAdvServiceData();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get service data.", 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, "Unable to remove manufacturer : " + manufacturerCode, e);
+ }
+ }
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index a2bb78c..e7ab8de 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -61,6 +61,7 @@ public final class BluetoothGatt implements BluetoothProfile {
private boolean mAutoConnect;
private int mConnState;
private final Object mStateLock = new Object();
+ private Boolean mDeviceBusy = false;
private static final int CONN_STATE_IDLE = 0;
private static final int CONN_STATE_CONNECTING = 1;
@@ -177,6 +178,10 @@ public final class BluetoothGatt implements BluetoothProfile {
mConnState = CONN_STATE_IDLE;
}
}
+
+ synchronized(mDeviceBusy) {
+ mDeviceBusy = false;
+ }
}
/**
@@ -312,6 +317,11 @@ public final class BluetoothGatt implements BluetoothProfile {
if (!address.equals(mDevice.getAddress())) {
return;
}
+
+ synchronized(mDeviceBusy) {
+ mDeviceBusy = false;
+ }
+
if ((status == GATT_INSUFFICIENT_AUTHENTICATION
|| status == GATT_INSUFFICIENT_ENCRYPTION)
&& mAuthRetry == false) {
@@ -359,6 +369,11 @@ public final class BluetoothGatt implements BluetoothProfile {
if (!address.equals(mDevice.getAddress())) {
return;
}
+
+ synchronized(mDeviceBusy) {
+ mDeviceBusy = false;
+ }
+
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType);
if (service == null) return;
@@ -436,6 +451,11 @@ public final class BluetoothGatt implements BluetoothProfile {
if (!address.equals(mDevice.getAddress())) {
return;
}
+
+ synchronized(mDeviceBusy) {
+ mDeviceBusy = false;
+ }
+
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType);
if (service == null) return;
@@ -485,6 +505,11 @@ public final class BluetoothGatt implements BluetoothProfile {
if (!address.equals(mDevice.getAddress())) {
return;
}
+
+ synchronized(mDeviceBusy) {
+ mDeviceBusy = false;
+ }
+
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType);
if (service == null) return;
@@ -530,6 +555,11 @@ public final class BluetoothGatt implements BluetoothProfile {
if (!address.equals(mDevice.getAddress())) {
return;
}
+
+ synchronized(mDeviceBusy) {
+ mDeviceBusy = false;
+ }
+
try {
mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
} catch (Exception ex) {
@@ -555,11 +585,29 @@ public final class BluetoothGatt implements BluetoothProfile {
}
/**
- * Listen command status callback
+ * Advertise state change callback
* @hide
*/
- public void onListen(int status) {
- if (DBG) Log.d(TAG, "onListen() - status=" + status);
+ public void onAdvertiseStateChange(int state, int status) {
+ if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = "
+ + state + " status=" + status);
+ }
+
+ /**
+ * Callback invoked when the MTU for a given connection changes
+ * @hide
+ */
+ public void onConfigureMTU(String address, int mtu, int status) {
+ if (DBG) Log.d(TAG, "onConfigureMTU() - Device=" + address +
+ " mtu=" + mtu + " status=" + status);
+ if (!address.equals(mDevice.getAddress())) {
+ return;
+ }
+ try {
+ mCallback.onConfigureMTU(BluetoothGatt.this, mtu, status);
+ } catch (Exception ex) {
+ Log.w(TAG, "Unhandled exception in callback", ex);
+ }
}
};
@@ -693,71 +741,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.
@@ -909,6 +892,11 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
try {
mService.readCharacteristic(mClientIf, device.getAddress(),
service.getType(), service.getInstanceId(),
@@ -916,6 +904,7 @@ public final class BluetoothGatt implements BluetoothProfile {
new ParcelUuid(characteristic.getUuid()), AUTHENTICATION_NONE);
} catch (RemoteException e) {
Log.e(TAG,"",e);
+ mDeviceBusy = false;
return false;
}
@@ -948,6 +937,11 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
try {
mService.writeCharacteristic(mClientIf, device.getAddress(),
service.getType(), service.getInstanceId(),
@@ -957,6 +951,7 @@ public final class BluetoothGatt implements BluetoothProfile {
characteristic.getValue());
} catch (RemoteException e) {
Log.e(TAG,"",e);
+ mDeviceBusy = false;
return false;
}
@@ -988,6 +983,11 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
try {
mService.readDescriptor(mClientIf, device.getAddress(), service.getType(),
service.getInstanceId(), new ParcelUuid(service.getUuid()),
@@ -996,6 +996,7 @@ public final class BluetoothGatt implements BluetoothProfile {
AUTHENTICATION_NONE);
} catch (RemoteException e) {
Log.e(TAG,"",e);
+ mDeviceBusy = false;
return false;
}
@@ -1026,6 +1027,11 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
try {
mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(),
service.getInstanceId(), new ParcelUuid(service.getUuid()),
@@ -1035,6 +1041,7 @@ public final class BluetoothGatt implements BluetoothProfile {
descriptor.getValue());
} catch (RemoteException e) {
Log.e(TAG,"",e);
+ mDeviceBusy = false;
return false;
}
@@ -1092,10 +1099,16 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
try {
mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
} catch (RemoteException e) {
Log.e(TAG,"",e);
+ mDeviceBusy = false;
return false;
}
@@ -1212,6 +1225,36 @@ public final class BluetoothGatt implements BluetoothProfile {
}
/**
+ * Configure the MTU used for a given connection.
+ *
+ * <p>When performing a write request operation (write without response),
+ * the data sent is truncated to the MTU size. This function may be used
+ * to request a larget MTU size to be able to send more data at once.
+ *
+ * <p>A {@link BluetoothGattCallback#onConfigureMTU} callback will indicate
+ * whether this operation was successful.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @return true, if the new MTU value has been requested successfully
+ * @hide
+ */
+ public boolean configureMTU(int mtu) {
+ if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
+ + " mtu: " + mtu);
+ if (mService == null || mClientIf == 0) return false;
+
+ try {
+ mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
* with {@link BluetoothProfile#GATT} as argument
*
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 80ea4a6..5180259 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -138,4 +138,19 @@ public abstract class BluetoothGattCallback {
*/
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
}
+
+ /**
+ * Callback indicating the MTU for a given device connection has changed.
+ *
+ * This callback is triggered in response to the
+ * {@link BluetoothGatt#configureMTU} function, or in response to a connection
+ * event.
+ *
+ * @param gatt GATT client invoked {@link BluetoothGatt#configureMTU}
+ * @param mtu The new MTU size
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully
+ * @hide
+ */
+ public void onConfigureMTU(BluetoothGatt gatt, int mtu, int status) {
+ }
}
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..c48b15d 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -76,6 +76,19 @@ 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_HANDSHAKE =
+ "android.bluetooth.input.profile.action.HANDSHAKE";
+
+ /**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_REPORT =
+ "android.bluetooth.input.profile.action.REPORT";
/**
* @hide
@@ -130,17 +143,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
@@ -180,6 +193,11 @@ public final class BluetoothInputDevice implements BluetoothProfile {
/**
* @hide
*/
+ public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS";
+
+ /**
+ * @hide
+ */
public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
private Context mContext;
@@ -603,7 +621,7 @@ public final class BluetoothInputDevice implements BluetoothProfile {
* @hide
*/
public boolean setReport(BluetoothDevice device, byte reportType, String report) {
- if (DBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
+ if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
if (mService != null && isEnabled() && isValidDevice(device)) {
try {
return mService.setReport(device, reportType, report);
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/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index a9b7176..7745bb7 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -61,6 +61,9 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
private static final boolean DBG = true;
private static final boolean VDBG = true;
+ // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
+ private static final int EVENT_NETWORK_FAILED = 1;
+
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
@@ -328,6 +331,7 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
}
if (!success) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+ mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
return;
}
mLinkProperties = dhcpResults.linkProperties;
@@ -420,6 +424,10 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
mBtdt.stopReverseTether();
break;
+ case EVENT_NETWORK_FAILED:
+ if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
+ mBtdt.teardown();
+ break;
}
}
}
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..c6b5c3d 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,
@@ -68,6 +73,7 @@ interface IBluetoothGatt {
void beginReliableWrite(in int clientIf, in String address);
void endReliableWrite(in int clientIf, in String address, in boolean execute);
void readRemoteRssi(in int clientIf, in String address);
+ void configureMTU(in int clientIf, in String address, in int mtu);
void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
void unregisterServer(in int serverIf);
@@ -75,7 +81,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..a78c29b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -63,5 +63,6 @@ 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);
+ oneway void onAdvertiseStateChange(in int advertiseState, in int status);
+ void onConfigureMTU(in String address, in int mtu, 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 *&#47;*.
* @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 44831fc..02c850b 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 *&#47;* 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 *&#47;*, 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 *&#47;*, 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 *&#47;*, 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 "*&#47;*". 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 "*&#47;*". 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 *&#47;*, 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 *&#47;*, 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/Context.java b/core/java/android/content/Context.java
index 2e4e209..5057cf4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -530,6 +530,9 @@ public abstract class Context {
* Open a private file associated with this Context's application package
* for writing. Creates the file if it doesn't already exist.
*
+ * <p>No permissions are required to invoke this method, since it uses internal
+ * storage.
+ *
* @param name The name of the file to open; can not contain path
* separators.
* @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
@@ -587,6 +590,9 @@ public abstract class Context {
* Returns the absolute path to the directory on the filesystem where
* files created with {@link #openFileOutput} are stored.
*
+ * <p>No permissions are required to read or write to the returned path, since this
+ * path is internal storage.
+ *
* @return The path of the directory holding application files.
*
* @see #openFileOutput
@@ -1798,7 +1804,7 @@ public abstract class Context {
* @hide like {@link #stopService(Intent)} but for a specific user.
*/
public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
-
+
/**
* Connect to an application service, creating it if needed. This defines
* a dependency between your application and the service. The given
@@ -1974,6 +1980,8 @@ public abstract class Context {
* @see android.app.SearchManager
* @see #SENSOR_SERVICE
* @see android.hardware.SensorManager
+ * @see #HDMI_CEC_SERVICE
+ * @see android.hardware.hdmi.HdmiCecManager
* @see #STORAGE_SERVICE
* @see android.os.storage.StorageManager
* @see #VIBRATOR_SERVICE
@@ -2389,6 +2397,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.hardware.hdmi.HdmiCecManager for controlling and managing
+ * HDMI-CEC protocol.
+ *
+ * @see #getSystemService
+ * @see android.hardware.hdmi.HdmiCecManager
+ */
+ public static final String HDMI_CEC_SERVICE = "hdmi_cec";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.hardware.input.InputManager} for interacting with input devices.
*
* @see #getSystemService
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2e2d4b8..95e27e2 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.
@@ -1414,15 +1414,38 @@ public class Intent implements Parcelable, Cloneable {
// Standard intent broadcast actions (see action variable).
/**
- * Broadcast Action: Sent after the screen turns off.
+ * Broadcast Action: Sent when the device goes to sleep and becomes non-interactive.
+ * <p>
+ * For historical reasons, the name of this broadcast action refers to the power
+ * state of the screen but it is actually sent in response to changes in the
+ * overall interactive state of the device.
+ * </p><p>
+ * This broadcast is sent when the device becomes non-interactive which may have
+ * nothing to do with the screen turning off. To determine the
+ * actual state of the screen, use {@link android.view.Display#getState}.
+ * </p><p>
+ * See {@link android.os.PowerManager#isInteractive} for details.
+ * </p>
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+
/**
- * Broadcast Action: Sent after the screen turns on.
+ * Broadcast Action: Sent when the device wakes up and becomes interactive.
+ * <p>
+ * For historical reasons, the name of this broadcast action refers to the power
+ * state of the screen but it is actually sent in response to changes in the
+ * overall interactive state of the device.
+ * </p><p>
+ * This broadcast is sent when the device becomes interactive which may have
+ * nothing to do with the screen turning on. To determine the
+ * actual state of the screen, use {@link android.view.Display#getState}.
+ * </p><p>
+ * See {@link android.os.PowerManager#isInteractive} for details.
+ * </p>
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -2765,6 +2788,12 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
/**
+ * Indicates an activity optimized for Leanback mode, and that should
+ * be displayed in the Leanback launcher.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+ /**
* Provides information about the package it is in; typically used if
* a package does not contain a {@link #CATEGORY_LAUNCHER} to provide
* a front-door to the user without having to be shown in the all apps list.
@@ -3547,6 +3576,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 +4458,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 +5474,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 "*&#47;*".
*
* @param clip The new clip to set. May be null to clear the current clip.
*/
@@ -7162,8 +7196,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/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b8ac3bf..941b726 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -187,7 +187,7 @@ public class ActivityInfo extends ComponentInfo
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
- * {@link android.R.attr#primaryUserOnly} attribute.
+ * android.R.attr#primaryUserOnly attribute.
*/
public static final int FLAG_PRIMARY_USER_ONLY = 0x20000000;
/**
@@ -199,6 +199,13 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int FLAG_SINGLE_USER = 0x40000000;
/**
+ * @hide Bit in {@link #flags}: If set, this activity may be launched into an
+ * owned ActivityContainer such as that within an ActivityView. If not set and
+ * this activity is launched into such a container a SecurityExcception will be
+ * thrown. Set from the {@link android.R.attr#allowEmbedded} attribute.
+ */
+ public static final int FLAG_ALLOW_EMBEDDED = 0x80000000;
+ /**
* Options that have been set in the activity declaration in the
* manifest.
* These include:
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1a1610d..0172509 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -315,6 +315,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_IS_DATA_ONLY = 1<<24;
/**
+ * Value for {@link #flags}: true if the application was declared to be a game, or
+ * false if it is a non-game application.
+ */
+ public static final int FLAG_IS_GAME = 1<<25;
+
+ /**
* Value for {@link #flags}: set to {@code true} if the application
* is permitted to hold privileged permissions.
*
@@ -363,7 +369,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
* {@link #FLAG_RESIZEABLE_FOR_SCREENS},
* {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
- * {@link #FLAG_INSTALLED}.
+ * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}.
*/
public int flags = 0;
@@ -483,7 +489,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* @hide
*/
public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-
+
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
if (className != null) {
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 4dbcf23..7e8f285 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -128,6 +128,17 @@ public class ComponentInfo extends PackageItemInfo {
return logo != 0 ? logo : applicationInfo.logo;
}
+ /**
+ * Return the banner resource identifier to use for this component. If the
+ * component defines a banner, that is used; else, the application banner is
+ * used.
+ *
+ * @return The banner associated with this component.
+ */
+ public final int getBannerResource() {
+ return banner != 0 ? banner : applicationInfo.banner;
+ }
+
protected void dumpFront(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
pw.println(prefix + "enabled=" + enabled + " exported=" + exported
@@ -175,6 +186,13 @@ public class ComponentInfo extends PackageItemInfo {
/**
* @hide
*/
+ @Override protected Drawable loadDefaultBanner(PackageManager pm) {
+ return applicationInfo.loadBanner(pm);
+ }
+
+ /**
+ * @hide
+ */
@Override
protected Drawable loadDefaultLogo(PackageManager pm) {
return applicationInfo.loadLogo(pm);
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index a67326e..58f1c84 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -68,6 +68,12 @@ public class PackageItemInfo {
/**
* A drawable resource identifier (in the package's resources) of this
+ * component's banner. From the "banner" attribute or, if not set, 0.
+ */
+ public int banner;
+
+ /**
+ * A drawable resource identifier (in the package's resources) of this
* component's logo. Logos may be larger/wider than icons and are
* displayed by certain UI elements in place of a name or name/icon
* combination. From the "logo" attribute or, if not set, 0.
@@ -92,6 +98,7 @@ public class PackageItemInfo {
nonLocalizedLabel = orig.nonLocalizedLabel;
if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim();
icon = orig.icon;
+ banner = orig.banner;
logo = orig.logo;
metaData = orig.metaData;
}
@@ -146,6 +153,27 @@ public class PackageItemInfo {
}
/**
+ * Retrieve the current graphical banner associated with this item. This
+ * will call back on the given PackageManager to load the banner from
+ * the application.
+ *
+ * @param pm A PackageManager from which the banner can be loaded; usually
+ * the PackageManager from which you originally retrieved this item.
+ *
+ * @return Returns a Drawable containing the item's banner. If the item
+ * does not have a banner, this method will return null.
+ */
+ public Drawable loadBanner(PackageManager pm) {
+ if (banner != 0) {
+ Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
+ if (dr != null) {
+ return dr;
+ }
+ }
+ return loadDefaultBanner(pm);
+ }
+
+ /**
* Retrieve the default graphical icon associated with this item.
*
* @param pm A PackageManager from which the icon can be loaded; usually
@@ -159,7 +187,22 @@ public class PackageItemInfo {
protected Drawable loadDefaultIcon(PackageManager pm) {
return pm.getDefaultActivityIcon();
}
-
+
+ /**
+ * Retrieve the default graphical banner associated with this item.
+ *
+ * @param pm A PackageManager from which the banner can be loaded; usually
+ * the PackageManager from which you originally retrieved this item.
+ *
+ * @return Returns a Drawable containing the item's default banner
+ * or null if no default logo is available.
+ *
+ * @hide
+ */
+ protected Drawable loadDefaultBanner(PackageManager pm) {
+ return null;
+ }
+
/**
* Retrieve the current graphical logo associated with this item. This
* will call back on the given PackageManager to load the logo from
@@ -224,10 +267,11 @@ public class PackageItemInfo {
pw.println(prefix + "name=" + name);
}
pw.println(prefix + "packageName=" + packageName);
- if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) {
+ if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
+ " nonLocalizedLabel=" + nonLocalizedLabel
- + " icon=0x" + Integer.toHexString(icon));
+ + " icon=0x" + Integer.toHexString(icon)
+ + " banner=0x" + Integer.toHexString(banner));
}
}
@@ -243,6 +287,7 @@ public class PackageItemInfo {
dest.writeInt(icon);
dest.writeInt(logo);
dest.writeBundle(metaData);
+ dest.writeInt(banner);
}
protected PackageItemInfo(Parcel source) {
@@ -254,6 +299,7 @@ public class PackageItemInfo {
icon = source.readInt();
logo = source.readInt();
metaData = source.readBundle();
+ banner = source.readInt();
}
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8ce7e97..226f5a6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -989,6 +989,7 @@ public abstract class PackageManager {
* @hide
* @deprecated
*/
+ @Deprecated
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
@@ -1244,6 +1245,26 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports leanback UI. This is
+ * typically used in a living room television experience, but is a software
+ * feature unlike {@link #FEATURE_TELEVISION}. Devices running with this
+ * feature will use resources associated with the "television" UI mode.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_LEANBACK = "android.software.leanback";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports only leanback UI. Only
+ * applications designed for this experience should be run, though this is
+ * not enforced by the system.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
*/
@SdkConstant(SdkConstantType.FEATURE)
@@ -1263,11 +1284,36 @@ public abstract class PackageManager {
* room television experience: displayed on a big screen, where the user
* is sitting far away from it, and the dominant form of input will be
* something like a DPAD, not through touch or mouse.
+ * @deprecated use {@link #FEATURE_LEANBACK} instead.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.FEATURE)
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
*/
@@ -1430,17 +1476,33 @@ public abstract class PackageManager {
public abstract Intent getLaunchIntentForPackage(String packageName);
/**
- * Return an array of all of the secondary group-ids that have been
- * assigned to a package.
- *
- * <p>Throws {@link NameNotFoundException} if a package with the given
- * name cannot be found on the system.
- *
+ * Return a "good" intent to launch a front-door Leanback activity in a
+ * package, for use for example to implement an "open" button when browsing
+ * through packages. The current implementation will look for a main
+ * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
+ * return null if no main leanback activities are found.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name
+ * cannot be found on the system.
+ *
+ * @param packageName The name of the package to inspect.
+ * @return Returns either a fully-qualified Intent that can be used to launch
+ * the main Leanback activity in the package, or null if the package
+ * does not contain such an activity.
+ */
+ public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
+
+ /**
+ * Return an array of all of the secondary group-ids that have been assigned
+ * to a package.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name
+ * cannot be found on the system.
+ *
* @param packageName The full name (i.e. com.google.apps.contacts) of the
- * desired package.
- *
- * @return Returns an int array of the assigned gids, or null if there
- * are none.
+ * desired package.
+ * @return Returns an int array of the assigned gids, or null if there are
+ * none.
*/
public abstract int[] getPackageGids(String packageName)
throws NameNotFoundException;
@@ -2388,6 +2450,40 @@ public abstract class PackageManager {
throws NameNotFoundException;
/**
+ * Retrieve the banner associated with an activity. Given the full name of
+ * an activity, retrieves the information about it and calls
+ * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its
+ * banner. If the activity cannot be found, NameNotFoundException is thrown.
+ *
+ * @param activityName Name of the activity whose banner is to be retrieved.
+ * @return Returns the image of the banner, or null if the activity has no
+ * banner specified.
+ * @throws NameNotFoundException Thrown if the resources for the given
+ * activity could not be loaded.
+ * @see #getActivityBanner(Intent)
+ */
+ public abstract Drawable getActivityBanner(ComponentName activityName)
+ throws NameNotFoundException;
+
+ /**
+ * Retrieve the banner associated with an Intent. If intent.getClassName()
+ * is set, this simply returns the result of
+ * getActivityBanner(intent.getClassName()). Otherwise it resolves the
+ * intent's component and returns the banner associated with the resolved
+ * component. If intent.getClassName() cannot be found or the Intent cannot
+ * be resolved to a component, NameNotFoundException is thrown.
+ *
+ * @param intent The intent for which you would like to retrieve a banner.
+ * @return Returns the image of the banner, or null if the activity has no
+ * banner specified.
+ * @throws NameNotFoundException Thrown if the resources for application
+ * matching the given intent could not be loaded.
+ * @see #getActivityBanner(ComponentName)
+ */
+ public abstract Drawable getActivityBanner(Intent intent)
+ throws NameNotFoundException;
+
+ /**
* Return the generic icon for an activity that is used when no specific
* icon is defined.
*
@@ -2428,19 +2524,43 @@ public abstract class PackageManager {
throws NameNotFoundException;
/**
- * Retrieve the logo associated with an activity. Given the full name of
- * an activity, retrieves the information about it and calls
- * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo.
- * If the activity cannot be found, NameNotFoundException is thrown.
- *
- * @param activityName Name of the activity whose logo is to be retrieved.
+ * Retrieve the banner associated with an application.
*
- * @return Returns the image of the logo or null if the activity has no
- * logo specified.
+ * @param info Information about application being queried.
+ * @return Returns the image of the banner or null if the application has no
+ * banner specified.
+ * @see #getApplicationBanner(String)
+ */
+ public abstract Drawable getApplicationBanner(ApplicationInfo info);
+
+ /**
+ * Retrieve the banner associated with an application. Given the name of the
+ * application's package, retrieves the information about it and calls
+ * getApplicationIcon() to return its banner. If the application cannot be
+ * found, NameNotFoundException is thrown.
*
+ * @param packageName Name of the package whose application banner is to be
+ * retrieved.
+ * @return Returns the image of the banner or null if the application has no
+ * banner specified.
* @throws NameNotFoundException Thrown if the resources for the given
- * activity could not be loaded.
+ * application could not be loaded.
+ * @see #getApplicationBanner(ApplicationInfo)
+ */
+ public abstract Drawable getApplicationBanner(String packageName)
+ throws NameNotFoundException;
+
+ /**
+ * Retrieve the logo associated with an activity. Given the full name of an
+ * activity, retrieves the information about it and calls
+ * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its
+ * logo. If the activity cannot be found, NameNotFoundException is thrown.
*
+ * @param activityName Name of the activity whose logo is to be retrieved.
+ * @return Returns the image of the logo or null if the activity has no logo
+ * specified.
+ * @throws NameNotFoundException Thrown if the resources for the given
+ * activity could not be loaded.
* @see #getActivityLogo(Intent)
*/
public abstract Drawable getActivityLogo(ComponentName activityName)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 52564eb..66d4f50 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -167,18 +167,20 @@ public class PackageParser {
final int labelRes;
final int iconRes;
final int logoRes;
+ final int bannerRes;
String tag;
TypedArray sa;
ParsePackageItemArgs(Package _owner, String[] _outError,
- int _nameRes, int _labelRes, int _iconRes, int _logoRes) {
+ int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
owner = _owner;
outError = _outError;
nameRes = _nameRes;
labelRes = _labelRes;
iconRes = _iconRes;
logoRes = _logoRes;
+ bannerRes = _bannerRes;
}
}
@@ -190,10 +192,10 @@ public class PackageParser {
int flags;
ParseComponentArgs(Package _owner, String[] _outError,
- int _nameRes, int _labelRes, int _iconRes, int _logoRes,
+ int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
String[] _sepProcesses, int _processRes,
int _descriptionRes, int _enabledRes) {
- super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes);
+ super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
sepProcesses = _sepProcesses;
processRes = _processRes;
descriptionRes = _descriptionRes;
@@ -1687,7 +1689,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
- com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) {
+ com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
+ com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
@@ -1730,7 +1733,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermission_name,
com.android.internal.R.styleable.AndroidManifestPermission_label,
com.android.internal.R.styleable.AndroidManifestPermission_icon,
- com.android.internal.R.styleable.AndroidManifestPermission_logo)) {
+ com.android.internal.R.styleable.AndroidManifestPermission_logo,
+ com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
@@ -1799,7 +1803,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
- com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) {
+ com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
+ com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
@@ -1844,7 +1849,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
- com.android.internal.R.styleable.AndroidManifestInstrumentation_logo);
+ com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
+ com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
mParseInstrumentationArgs.tag = "<instrumentation>";
}
@@ -1960,6 +1966,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
ai.logo = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
+ ai.banner = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
ai.theme = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
ai.descriptionRes = sa.getResourceId(
@@ -2081,6 +2089,11 @@ public class PackageParser {
ai.enabled = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
+ ai.flags |= ApplicationInfo.FLAG_IS_GAME;
+ }
+
if (false) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
@@ -2253,7 +2266,7 @@ public class PackageParser {
private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
String[] outError, String tag, TypedArray sa,
- int nameRes, int labelRes, int iconRes, int logoRes) {
+ int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
String name = sa.getNonConfigurationString(nameRes, 0);
if (name == null) {
outError[0] = tag + " does not specify android:name";
@@ -2277,6 +2290,11 @@ public class PackageParser {
outInfo.logo = logoVal;
}
+ int bannerVal = sa.getResourceId(bannerRes, 0);
+ if (bannerVal != 0) {
+ outInfo.banner = bannerVal;
+ }
+
TypedValue v = sa.peekValue(labelRes);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
outInfo.nonLocalizedLabel = v.coerceToString();
@@ -2300,6 +2318,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivity_label,
com.android.internal.R.styleable.AndroidManifestActivity_icon,
com.android.internal.R.styleable.AndroidManifestActivity_logo,
+ com.android.internal.R.styleable.AndroidManifestActivity_banner,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestActivity_process,
com.android.internal.R.styleable.AndroidManifestActivity_description,
@@ -2426,6 +2445,12 @@ public class PackageParser {
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
@@ -2585,6 +2610,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
+ com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
mSeparateProcesses,
0,
com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
@@ -2619,6 +2645,7 @@ public class PackageParser {
info.flags = target.info.flags;
info.icon = target.info.icon;
info.logo = target.info.logo;
+ info.banner = target.info.banner;
info.labelRes = target.info.labelRes;
info.nonLocalizedLabel = target.info.nonLocalizedLabel;
info.launchMode = target.info.launchMode;
@@ -2732,6 +2759,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestProvider_label,
com.android.internal.R.styleable.AndroidManifestProvider_icon,
com.android.internal.R.styleable.AndroidManifestProvider_logo,
+ com.android.internal.R.styleable.AndroidManifestProvider_banner,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestProvider_process,
com.android.internal.R.styleable.AndroidManifestProvider_description,
@@ -3038,6 +3066,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestService_label,
com.android.internal.R.styleable.AndroidManifestService_icon,
com.android.internal.R.styleable.AndroidManifestService_logo,
+ com.android.internal.R.styleable.AndroidManifestService_banner,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestService_process,
com.android.internal.R.styleable.AndroidManifestService_description,
@@ -3335,6 +3364,9 @@ public class PackageParser {
outInfo.logo = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
+ outInfo.banner = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
+
sa.recycle();
int outerDepth = parser.getDepth();
@@ -3701,6 +3733,11 @@ public class PackageParser {
outInfo.logo = logoVal;
}
+ int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
+ if (bannerVal != 0) {
+ outInfo.banner = bannerVal;
+ }
+
TypedValue v = args.sa.peekValue(args.labelRes);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
outInfo.nonLocalizedLabel = v.coerceToString();
@@ -4125,6 +4162,7 @@ public class PackageParser {
public CharSequence nonLocalizedLabel;
public int icon;
public int logo;
+ public int banner;
public int preferred;
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 48b6fca..a07fc97 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -440,6 +440,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
* resource qualifier. */
public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
+ /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+ * value that corresponds to the
+ * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a>
+ * resource qualifier. */
+ public static final int UI_MODE_TYPE_WATCH = 0x06;
/** Constant for {@link #uiMode}: bits that encode the night mode. */
public static final int UI_MODE_NIGHT_MASK = 0x30;
@@ -462,8 +467,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
* device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
* {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
- * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, or
- * {@link #UI_MODE_TYPE_APPLIANCE}.
+ * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION},
+ * {@link #UI_MODE_TYPE_APPLIANCE}, or {@link #UI_MODE_TYPE_WATCH}.
*
* <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
* is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
@@ -700,6 +705,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
case UI_MODE_TYPE_CAR: sb.append(" car"); break;
case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
+ case UI_MODE_TYPE_WATCH: sb.append(" watch"); break;
default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
}
switch ((uiMode&UI_MODE_NIGHT_MASK)) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 3d9daca..7318652 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1461,6 +1461,11 @@ public class Resources {
private final AssetManager mAssets;
private final long mTheme;
+
+ // Needed by layoutlib.
+ /*package*/ long getNativeTheme() {
+ return mTheme;
+ }
}
/**
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/Camera.java b/core/java/android/hardware/Camera.java
index 111062d..eae4a46 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -45,6 +45,7 @@ import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -2150,10 +2151,20 @@ public class Camera {
private static final String PIXEL_FORMAT_JPEG = "jpeg";
private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb";
- private HashMap<String, String> mMap;
+ /**
+ * Order matters: Keys that are {@link #set(String, String) set} later
+ * will take precedence over keys that are set earlier (if the two keys
+ * conflict with each other).
+ *
+ * <p>One example is {@link #setPreviewFpsRange(int, int)} , since it
+ * conflicts with {@link #setPreviewFrameRate(int)} whichever key is set later
+ * is the one that will take precedence.
+ * </p>
+ */
+ private final LinkedHashMap<String, String> mMap;
private Parameters() {
- mMap = new HashMap<String, String>(64);
+ mMap = new LinkedHashMap<String, String>(/*initialCapacity*/64);
}
/**
@@ -2233,7 +2244,7 @@ public class Camera {
return;
}
- mMap.put(key, value);
+ put(key, value);
}
/**
@@ -2243,7 +2254,18 @@ public class Camera {
* @param value the int value of the parameter
*/
public void set(String key, int value) {
- mMap.put(key, Integer.toString(value));
+ put(key, Integer.toString(value));
+ }
+
+ private void put(String key, String value) {
+ /*
+ * Remove the key if it already exists.
+ *
+ * This way setting a new value for an already existing key will always move
+ * that key to be ordered the latest in the map.
+ */
+ mMap.remove(key);
+ mMap.put(key, value);
}
private void set(String key, List<Area> areas) {
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 89a5819..4bea9ee 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -38,6 +38,13 @@ public final class Sensor {
public static final int TYPE_ACCELEROMETER = 1;
/**
+ * A constant string describing an accelerometer sensor type.
+ *
+ * @see #TYPE_ACCELEROMETER
+ */
+ public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+
+ /**
* A constant describing a magnetic field sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -45,6 +52,13 @@ public final class Sensor {
public static final int TYPE_MAGNETIC_FIELD = 2;
/**
+ * A constant string describing a magnetic field sensor type.
+ *
+ * @see #TYPE_MAGNETIC_FIELD
+ */
+ public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+
+ /**
* A constant describing an orientation sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -55,24 +69,58 @@ public final class Sensor {
@Deprecated
public static final int TYPE_ORIENTATION = 3;
- /** A constant describing a gyroscope sensor type.
+ /**
+ * A constant string describing an orientation sensor type.
+ *
+ * @see #TYPE_ORIENTATION
+ * @deprecated use {@link android.hardware.SensorManager#getOrientation
+ * SensorManager.getOrientation()} instead.
+ */
+ @Deprecated
+ public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+
+ /**
+ * A constant describing a gyroscope sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details. */
public static final int TYPE_GYROSCOPE = 4;
/**
+ * A constant string describing a gyroscope sensor type.
+ *
+ * @see #TYPE_GYROSCOPE
+ */
+ public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+
+ /**
* A constant describing a light sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
*/
public static final int TYPE_LIGHT = 5;
- /** A constant describing a pressure sensor type.
+ /**
+ * A constant string describing a light sensor type.
+ *
+ * @see #TYPE_LIGHT
+ */
+ public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+
+ /**
+ * A constant describing a pressure sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
- * for more details. */
+ * for more details.
+ */
public static final int TYPE_PRESSURE = 6;
/**
+ * A constant string describing a pressure sensor type.
+ *
+ * @see #TYPE_PRESSURE
+ */
+ public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+
+ /**
* A constant describing a temperature sensor type
*
* @deprecated use
@@ -83,6 +131,17 @@ public final class Sensor {
public static final int TYPE_TEMPERATURE = 7;
/**
+ * A constant string describing a temperature sensor type
+ *
+ * @see #TYPE_TEMPERATURE
+ * @deprecated use
+ * {@link android.hardware.Sensor#STRING_TYPE_AMBIENT_TEMPERATURE
+ * Sensor.STRING_TYPE_AMBIENT_TEMPERATURE} instead.
+ */
+ @Deprecated
+ public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+
+ /**
* A constant describing a proximity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -90,6 +149,13 @@ public final class Sensor {
public static final int TYPE_PROXIMITY = 8;
/**
+ * A constant string describing a proximity sensor type.
+ *
+ * @see #TYPE_PROXIMITY
+ */
+ public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+
+ /**
* A constant describing a gravity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -97,6 +163,13 @@ public final class Sensor {
public static final int TYPE_GRAVITY = 9;
/**
+ * A constant string describing a gravity sensor type.
+ *
+ * @see #TYPE_GRAVITY
+ */
+ public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+
+ /**
* A constant describing a linear acceleration sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -104,6 +177,14 @@ public final class Sensor {
public static final int TYPE_LINEAR_ACCELERATION = 10;
/**
+ * A constant string describing a linear acceleration sensor type.
+ *
+ * @see #TYPE_LINEAR_ACCELERATION
+ */
+ public static final String STRING_TYPE_LINEAR_ACCELERATION =
+ "android.sensor.linear_acceleration";
+
+ /**
* A constant describing a rotation vector sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -111,18 +192,42 @@ public final class Sensor {
public static final int TYPE_ROTATION_VECTOR = 11;
/**
+ * A constant string describing a rotation vector sensor type.
+ *
+ * @see #TYPE_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+
+ /**
* A constant describing a relative humidity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
*/
public static final int TYPE_RELATIVE_HUMIDITY = 12;
- /** A constant describing an ambient temperature sensor type.
+ /**
+ * A constant string describing a relative humidity sensor type
+ *
+ * @see #TYPE_RELATIVE_HUMIDITY
+ */
+ public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+
+ /**
+ * A constant describing an ambient temperature sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
- * for more details. */
+ * for more details.
+ */
public static final int TYPE_AMBIENT_TEMPERATURE = 13;
/**
+ * A constant string describing an ambient temperature sensor type.
+ *
+ * @see #TYPE_AMBIENT_TEMPERATURE
+ */
+ public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
+ "android.sensor.ambient_temperature";
+
+ /**
* A constant describing an uncalibrated magnetic field sensor type.
* <p>
* Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration
@@ -139,6 +244,13 @@ public final class Sensor {
* details.
*/
public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
+ /**
+ * A constant string describing an uncalibrated magnetic field sensor type.
+ *
+ * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+ */
+ public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
+ "android.sensor.magnetic_field_uncalibrated";
/**
* A constant describing an uncalibrated rotation vector sensor type.
@@ -156,10 +268,17 @@ public final class Sensor {
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more
* details.
*/
-
public static final int TYPE_GAME_ROTATION_VECTOR = 15;
/**
+ * A constant string describing an uncalibrated rotation vector sensor type.
+ *
+ * @see #TYPE_GAME_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
+ "android.sensor.game_rotation_vector";
+
+ /**
* A constant describing an uncalibrated gyroscope sensor type.
* <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed
* to adjust the given sensor values. However, such gyro-drift bias values
@@ -174,6 +293,14 @@ public final class Sensor {
public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
/**
+ * A constant string describing an uncalibrated gyroscope sensor type.
+ *
+ * @see #TYPE_GYROSCOPE_UNCALIBRATED
+ */
+ public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
+ "android.sensor.gyroscope_uncalibrated";
+
+ /**
* A constant describing a significant motion trigger sensor.
* <p>
* It triggers when an event occurs and then automatically disables
@@ -186,6 +313,14 @@ public final class Sensor {
public static final int TYPE_SIGNIFICANT_MOTION = 17;
/**
+ * A constant string describing a significant motion trigger sensor.
+ *
+ * @see #TYPE_SIGNIFICANT_MOTION
+ */
+ public static final String STRING_TYPE_SIGNIFICANT_MOTION =
+ "android.sensor.significant_motion";
+
+ /**
* A constant describing a step detector sensor.
* <p>
* A sensor of this type triggers an event each time a step is taken by the user. The only
@@ -198,6 +333,13 @@ public final class Sensor {
public static final int TYPE_STEP_DETECTOR = 18;
/**
+ * A constant string describing a step detector sensor.
+ *
+ * @see #TYPE_STEP_DETECTOR
+ */
+ public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+
+ /**
* A constant describing a step counter sensor.
* <p>
* A sensor of this type returns the number of steps taken by the user since the last reboot
@@ -211,7 +353,14 @@ public final class Sensor {
public static final int TYPE_STEP_COUNTER = 19;
/**
- * A constant describing the geo-magnetic rotation vector.
+ * A constant string describing a step counter sensor.
+ *
+ * @see #TYPE_STEP_COUNTER
+ */
+ public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+
+ /**
+ * A constant describing a geo-magnetic rotation vector.
* <p>
* Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
* gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
@@ -222,6 +371,32 @@ public final class Sensor {
public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
/**
+ * A constant string describing a geo-magnetic rotation vector.
+ *
+ * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
+ "android.sensor.geomagnetic_rotation_vector";
+
+ /**
+ * A constant describing a heart rate monitor.
+ * <p>
+ * A sensor that measures the heart rate in beats per minute.
+ * <p>
+ * value[0] represents the beats per minute when the measurement was taken.
+ * value[0] is 0 if the heart rate monitor could not measure the rate or the
+ * rate is 0 beat per minute.
+ */
+ public static final int TYPE_HEART_RATE = 21;
+
+ /**
+ * A constant string describing a heart rate monitor.
+ *
+ * @see #TYPE_HEART_RATE
+ */
+ public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+
+ /**
* A constant describing all sensor types.
*/
public static final int TYPE_ALL = -1;
@@ -265,7 +440,8 @@ public final class Sensor {
// added post 4.3
REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_DETECTOR
REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5 // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ REPORTING_MODE_ON_CHANGE, 1 // SENSOR_TYPE_HEART_RATE_MONITOR
};
static int getReportingMode(Sensor sensor) {
@@ -321,6 +497,8 @@ public final class Sensor {
private int mMinDelay;
private int mFifoReservedEventCount;
private int mFifoMaxEventCount;
+ private String mStringType;
+ private String mRequiredPermission;
Sensor() {
}
@@ -401,6 +579,20 @@ public final class Sensor {
return mFifoMaxEventCount;
}
+ /**
+ * @return The type of this sensor as a string.
+ */
+ public String getStringType() {
+ return mStringType;
+ }
+
+ /**
+ * @return The permission required to access this sensor. If empty, no permission is required.
+ */
+ public String getRequiredPermission() {
+ return mRequiredPermission;
+ }
+
/** @hide */
public int getHandle() {
return mHandle;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index ac9189d..5f2b5f0 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..79673b3 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();
}
/**
@@ -405,6 +437,14 @@ public final class DisplayManager {
* The behavior of the virtual display depends on the flags that are provided
* to this method. By default, virtual displays are created to be private,
* non-presentation and unsecure. Permissions may be required to use certain flags.
+ * </p><p>
+ * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may
+ * be attached or detached dynamically using {@link VirtualDisplay#setSurface}.
+ * Previously, the surface had to be non-null when {@link #createVirtualDisplay}
+ * was called and could not be changed for the lifetime of the display.
+ * </p><p>
+ * Detaching the surface that backs a virtual display has a similar effect to
+ * turning off the screen.
* </p>
*
* @param name The name of the virtual display, must be non-empty.
@@ -412,10 +452,10 @@ public final class DisplayManager {
* @param height The height of the virtual display in pixels, must be greater than 0.
* @param densityDpi The density of the virtual display in dpi, must be greater than 0.
* @param surface The surface to which the content of the virtual display should
- * be rendered, must be non-null.
+ * be rendered, or null if there is none initially.
* @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..a8d55e8 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;
+ }
}
}
@@ -354,9 +377,6 @@ public final class DisplayManagerGlobal {
throw new IllegalArgumentException("width, height, and densityDpi must be "
+ "greater than 0");
}
- if (surface == null) {
- throw new IllegalArgumentException("surface must not be null");
- }
Binder token = new Binder();
int displayId;
@@ -381,7 +401,15 @@ public final class DisplayManagerGlobal {
}
return null;
}
- return new VirtualDisplay(this, display, token);
+ return new VirtualDisplay(this, display, token, surface);
+ }
+
+ public void setVirtualDisplaySurface(IBinder token, Surface surface) {
+ try {
+ mDm.setVirtualDisplaySurface(token, surface);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to set virtual display surface.", ex);
+ }
}
public void releaseVirtualDisplay(IBinder token) {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
new file mode 100644
index 0000000..cec90cd
--- /dev/null
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -0,0 +1,261 @@
+/*
+ * 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.hardware.SensorManager;
+import android.os.Handler;
+import android.os.PowerManager;
+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 initialize power management facilities.
+ */
+ public abstract void initPowerManagement(DisplayPowerCallbacks callbacks,
+ Handler handler, SensorManager sensorManager);
+
+ /**
+ * Called by the power manager to request a new power state.
+ * <p>
+ * The display power controller makes a copy of the provided object and then
+ * begins adjusting the power state to match what was requested.
+ * </p>
+ *
+ * @param request The requested power state.
+ * @param waitForNegativeProximity If true, issues a request to wait for
+ * negative proximity before turning the screen back on, assuming the screen
+ * was turned off by the proximity sensor.
+ * @return True if display is ready, false if there are important changes that must
+ * be made asynchronously (such as turning the screen on), in which case the caller
+ * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
+ * then try the request again later until the state converges.
+ */
+ public abstract boolean requestPowerState(DisplayPowerRequest request,
+ boolean waitForNegativeProximity);
+
+ /**
+ * Returns true if the proximity sensor screen-off function is available.
+ */
+ public abstract boolean isProximitySensorAvailable();
+
+ /**
+ * 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);
+
+ /**
+ * Describes the requested power state of the display.
+ *
+ * This object is intended to describe the general characteristics of the
+ * power state, such as whether the screen should be on or off and the current
+ * brightness controls leaving the DisplayPowerController to manage the
+ * details of how the transitions between states should occur. The goal is for
+ * the PowerManagerService to focus on the global power state and not
+ * have to micro-manage screen off animations, auto-brightness and other effects.
+ */
+ public static final class DisplayPowerRequest {
+ public static final int SCREEN_STATE_OFF = 0;
+ public static final int SCREEN_STATE_DOZE = 1;
+ public static final int SCREEN_STATE_DIM = 2;
+ public static final int SCREEN_STATE_BRIGHT = 3;
+
+ // The requested minimum screen power state: off, doze, dim or bright.
+ public int screenState;
+
+ // If true, the proximity sensor overrides the screen state when an object is
+ // nearby, turning it off temporarily until the object is moved away.
+ public boolean useProximitySensor;
+
+ // The desired screen brightness in the range 0 (minimum / off) to 255 (brightest).
+ // The display power controller may choose to clamp the brightness.
+ // When auto-brightness is enabled, this field should specify a nominal default
+ // value to use while waiting for the light sensor to report enough data.
+ public int screenBrightness;
+
+ // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter).
+ public float screenAutoBrightnessAdjustment;
+
+ // If true, enables automatic brightness control.
+ public boolean useAutoBrightness;
+
+ // If true, prevents the screen from completely turning on if it is currently off.
+ // The display does not enter a "ready" state if this flag is true and screen on is
+ // blocked. The window manager policy blocks screen on while it prepares the keyguard to
+ // prevent the user from seeing intermediate updates.
+ //
+ // Technically, we may not block the screen itself from turning on (because that introduces
+ // extra unnecessary latency) but we do prevent content on screen from becoming
+ // visible to the user.
+ public boolean blockScreenOn;
+
+ public DisplayPowerRequest() {
+ screenState = SCREEN_STATE_BRIGHT;
+ useProximitySensor = false;
+ screenBrightness = PowerManager.BRIGHTNESS_ON;
+ screenAutoBrightnessAdjustment = 0.0f;
+ useAutoBrightness = false;
+ blockScreenOn = false;
+ }
+
+ public DisplayPowerRequest(DisplayPowerRequest other) {
+ copyFrom(other);
+ }
+
+ // Returns true if we want the screen on in any mode, including doze.
+ public boolean wantScreenOnAny() {
+ return screenState != SCREEN_STATE_OFF;
+ }
+
+ // Returns true if we want the screen on in a normal mode, excluding doze.
+ // This is usually what we want to tell the rest of the system. For compatibility
+ // reasons, we pretend the screen is off when dozing.
+ public boolean wantScreenOnNormal() {
+ return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
+ }
+
+ public boolean wantLightSensorEnabled() {
+ // Specifically, we don't want the light sensor while dozing.
+ return useAutoBrightness && wantScreenOnNormal();
+ }
+
+ public void copyFrom(DisplayPowerRequest other) {
+ screenState = other.screenState;
+ useProximitySensor = other.useProximitySensor;
+ screenBrightness = other.screenBrightness;
+ screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
+ useAutoBrightness = other.useAutoBrightness;
+ blockScreenOn = other.blockScreenOn;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof DisplayPowerRequest
+ && equals((DisplayPowerRequest)o);
+ }
+
+ public boolean equals(DisplayPowerRequest other) {
+ return other != null
+ && screenState == other.screenState
+ && useProximitySensor == other.useProximitySensor
+ && screenBrightness == other.screenBrightness
+ && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
+ && useAutoBrightness == other.useAutoBrightness
+ && blockScreenOn == other.blockScreenOn;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0; // don't care
+ }
+
+ @Override
+ public String toString() {
+ return "screenState=" + screenState
+ + ", useProximitySensor=" + useProximitySensor
+ + ", screenBrightness=" + screenBrightness
+ + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+ + ", useAutoBrightness=" + useAutoBrightness
+ + ", blockScreenOn=" + blockScreenOn;
+ }
+ }
+
+ /**
+ * Asynchronous callbacks from the power controller to the power manager service.
+ */
+ public interface DisplayPowerCallbacks {
+ void onStateChanged();
+ void onProximityPositive();
+ void onProximityNegative();
+ void onDisplayStateChange(int state); // one of the Display state constants
+
+ void acquireSuspendBlocker();
+ void releaseSuspendBlocker();
+ }
+
+ /**
+ * 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..23c58c8 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();
@@ -54,11 +63,8 @@ interface IDisplayManager {
String name, int width, int height, int densityDpi, in Surface surface, int flags);
// No permissions required but must be same Uid as the creator.
- void releaseVirtualDisplay(in IBinder token);
-
- // Requires CONFIGURE_WIFI_DISPLAY permission.
- void pauseWifiDisplay();
+ void setVirtualDisplaySurface(in IBinder token, in Surface surface);
- // Requires CONFIGURE_WIFI_DISPLAY permission.
- void resumeWifiDisplay();
+ // No permissions required but must be same Uid as the creator.
+ void releaseVirtualDisplay(in IBinder token);
}
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 01e5bac..691d6a0 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -17,15 +17,18 @@ package android.hardware.display;
import android.os.IBinder;
import android.view.Display;
+import android.view.Surface;
/**
* Represents a virtual display. The content of a virtual display is rendered to a
* {@link android.view.Surface} that you must provide to {@link DisplayManager#createVirtualDisplay
* createVirtualDisplay()}.
- * <p>Because a virtual display renders to a surface provided by the application, it will be
+ * <p>
+ * Because a virtual display renders to a surface provided by the application, it will be
* released automatically when the process terminates and all remaining windows on it will
- * be forcibly removed. However, you should also explicitly call {@link #release} when you're
- * done with it.
+ * be forcibly removed. However, you should also explicitly call {@link #release} when
+ * you're done with it.
+ * </p>
*
* @see DisplayManager#createVirtualDisplay
*/
@@ -33,11 +36,14 @@ public final class VirtualDisplay {
private final DisplayManagerGlobal mGlobal;
private final Display mDisplay;
private IBinder mToken;
+ private Surface mSurface;
- VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token) {
+ VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token,
+ Surface surface) {
mGlobal = global;
mDisplay = display;
mToken = token;
+ mSurface = surface;
}
/**
@@ -48,6 +54,32 @@ public final class VirtualDisplay {
}
/**
+ * Gets the surface that backs the virtual display.
+ */
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ /**
+ * Sets the surface that backs the virtual display.
+ * <p>
+ * Detaching the surface that backs a virtual display has a similar effect to
+ * turning off the screen.
+ * </p><p>
+ * It is still the caller's responsibility to destroy the surface after it has
+ * been detached.
+ * </p>
+ *
+ * @param surface The surface to set, or null to detach the surface from the virtual display.
+ */
+ public void setSurface(Surface surface) {
+ if (mSurface != surface) {
+ mGlobal.setVirtualDisplaySurface(mToken, surface);
+ mSurface = surface;
+ }
+ }
+
+ /**
* Releases the virtual display and destroys its underlying surface.
* <p>
* All remaining windows on the virtual display will be forcibly removed
@@ -63,6 +95,7 @@ public final class VirtualDisplay {
@Override
public String toString() {
- return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken + "}";
+ return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
+ + ", surface=" + mSurface + "}";
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
new file mode 100644
index 0000000..8578a32
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -0,0 +1,257 @@
+/*
+ * 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.hdmi;
+
+/**
+ * Defines constants and utility methods related to HDMI-CEC protocol.
+ */
+public final class HdmiCec {
+
+ /** TV device type. */
+ public static final int DEVICE_TV = 0;
+
+ /** Recording device type. */
+ public static final int DEVICE_RECORDER = 1;
+
+ /** Device type reserved for future usage. */
+ public static final int DEVICE_RESERVED = 2;
+
+ /** Tuner device type. */
+ public static final int DEVICE_TUNER = 3;
+
+ /** Playback device type. */
+ public static final int DEVICE_PLAYBACK = 4;
+
+ /** Audio system device type. */
+ public static final int DEVICE_AUDIO_SYSTEM = 5;
+
+ // Value indicating the device is not an active source.
+ public static final int DEVICE_INACTIVE = -1;
+
+ /** Logical address for TV */
+ public static final int ADDR_TV = 0;
+
+ /** Logical address for recorder 1 */
+ public static final int ADDR_RECORDER_1 = 1;
+
+ /** Logical address for recorder 2 */
+ public static final int ADDR_RECORDER_2 = 2;
+
+ /** Logical address for tuner 1 */
+ public static final int ADDR_TUNER_1 = 3;
+
+ /** Logical address for playback 1 */
+ public static final int ADDR_PLAYBACK_1 = 4;
+
+ /** Logical address for audio system */
+ public static final int ADDR_AUDIO_SYSTEM = 5;
+
+ /** Logical address for tuner 2 */
+ public static final int ADDR_TUNER_2 = 6;
+
+ /** Logical address for tuner 3 */
+ public static final int ADDR_TUNER_3 = 7;
+
+ /** Logical address for playback 2 */
+ public static final int ADDR_PLAYBACK_2 = 8;
+
+ /** Logical address for recorder 3 */
+ public static final int ADDR_RECORDER_3 = 9;
+
+ /** Logical address for tuner 4 */
+ public static final int ADDR_TUNER_4 = 10;
+
+ /** Logical address for playback 3 */
+ public static final int ADDR_PLAYBACK_3 = 11;
+
+ /** Logical address reserved for future usage */
+ public static final int ADDR_RESERVED_1 = 12;
+
+ /** Logical address reserved for future usage */
+ public static final int ADDR_RESERVED_2 = 13;
+
+ /** Logical address for TV other than the one assigned with {@link #ADDR_TV} */
+ public static final int ADDR_FREE_USE = 14;
+
+ /** Logical address for devices to which address cannot be allocated */
+ public static final int ADDR_UNREGISTERED = 15;
+
+ /** Logical address used in the destination address field for broadcast messages */
+ public static final int ADDR_BROADCAST = 15;
+
+ /** Logical address used to indicate it is not initialized or invalid. */
+ public static final int ADDR_INVALID = -1;
+
+ // TODO: Complete the list of CEC messages definition.
+ public static final int MESSAGE_FEATURE_ABORT = 0x00;
+ public static final int MESSAGE_IMAGE_VIEW_ON = 0x04;
+ public static final int MESSAGE_TUNER_STEP_INCREMENT = 0x05;
+ public static final int MESSAGE_TUNER_STEP_DECREMENT = 0x06;
+ public static final int MESSAGE_TUNER_DEVICE_STATUS = 0x07;
+ public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 0x08;
+ public static final int MESSAGE_RECORD_ON = 0x09;
+ public static final int MESSAGE_RECORD_STATUS = 0x0A;
+ public static final int MESSAGE_RECORD_OFF = 0x0B;
+ public static final int MESSAGE_TEXT_VIEW_ON = 0x0D;
+ public static final int MESSAGE_RECORD_TV_SCREEN = 0x0F;
+ public static final int MESSAGE_GIVE_DECK_STATUS = 0x1A;
+ public static final int MESSAGE_DECK_STATUS = 0x1B;
+ public static final int MESSAGE_SET_MENU_LANGUAGE = 0x32;
+ public static final int MESSAGE_CLEAR_ANALOG_TIMER = 0x33;
+ public static final int MESSAGE_SET_ANALOG_TIMER = 0x34;
+ public static final int MESSAGE_TIMER_STATUS = 0x35;
+ public static final int MESSAGE_STANDBY = 0x36;
+ public static final int MESSAGE_PLAY = 0x41;
+ public static final int MESSAGE_DECK_CONTROL = 0x42;
+ public static final int MESSAGE_TIMER_CLEARED_STATUS = 0x043;
+ public static final int MESSAGE_USER_CONTROL_PRESSED = 0x44;
+ public static final int MESSAGE_USER_CONTROL_RELEASED = 0x45;
+ public static final int MESSAGE_GET_OSD_NAME = 0x46;
+ public static final int MESSAGE_SET_OSD_NAME = 0x47;
+ public static final int MESSAGE_SET_OSD_STRING = 0x64;
+ public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 0x67;
+ public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 0x70;
+ public static final int MESSAGE_GIVE_AUDIO_STATUS = 0x71;
+ public static final int MESSAGE_SET_SYSTEM_AUDIO_MODE = 0x72;
+ public static final int MESSAGE_REPORT_AUDIO_STATUS = 0x7A;
+ public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D;
+ public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 0x7E;
+ public static final int MESSAGE_ROUTING_CHANGE = 0x80;
+ public static final int MESSAGE_ROUTING_INFORMATION = 0x81;
+ public static final int MESSAGE_ACTIVE_SOURCE = 0x82;
+ public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 0x83;
+ public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 0x84;
+ public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 0x85;
+ public static final int MESSAGE_SET_STREAM_PATH = 0x86;
+ public static final int MESSAGE_DEVICE_VENDOR_ID = 0x87;
+ public static final int MESSAGE_VENDOR_COMMAND = 0x89;
+ public static final int MESSAGE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A;
+ public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 0x8B;
+ public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 0x8C;
+ public static final int MESSAGE_MENU_REQUEST = 0x8D;
+ public static final int MESSAGE_MENU_STATUS = 0x8E;
+ public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 0x8F;
+ public static final int MESSAGE_REPORT_POWER_STATUS = 0x90;
+ public static final int MESSAGE_GET_MENU_LANGUAGE = 0x91;
+ public static final int MESSAGE_SELECT_ANALOG_SERVICE = 0x92;
+ public static final int MESSAGE_SELECT_DIGITAL_SERVICE = 0x93;
+ public static final int MESSAGE_SET_DIGITAL_TIMER = 0x97;
+ public static final int MESSAGE_CLEAR_DIGITAL_TIMER = 0x99;
+ public static final int MESSAGE_SET_AUDIO_RATE = 0x9A;
+ public static final int MESSAGE_INACTIVE_SOURCE = 0x9D;
+ public static final int MESSAGE_CEC_VERSION = 0x9E;
+ public static final int MESSAGE_GET_CEC_VERSION = 0x9F;
+ public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 0xA0;
+ public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 0xA1;
+ public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
+ public static final int MESSAGE_ABORT = 0xFF;
+
+ public static final int POWER_STATUS_UNKNOWN = -1;
+ public static final int POWER_STATUS_ON = 0;
+ public static final int POWER_STATUS_STANDBY = 1;
+ public static final int POWER_TRANSIENT_TO_ON = 2;
+ public static final int POWER_TRANSIENT_TO_STANDBY = 3;
+
+ private static final int[] ADDRESS_TO_TYPE = {
+ DEVICE_TV, // ADDR_TV
+ DEVICE_RECORDER, // ADDR_RECORDER_1
+ DEVICE_RECORDER, // ADDR_RECORDER_2
+ DEVICE_TUNER, // ADDR_TUNER_1
+ DEVICE_PLAYBACK, // ADDR_PLAYBACK_1
+ DEVICE_AUDIO_SYSTEM, // ADDR_AUDIO_SYSTEM
+ DEVICE_TUNER, // ADDR_TUNER_2
+ DEVICE_TUNER, // ADDR_TUNER_3
+ DEVICE_PLAYBACK, // ADDR_PLAYBACK_2
+ DEVICE_RECORDER, // ADDR_RECORDER_3
+ DEVICE_TUNER, // ADDR_TUNER_4
+ DEVICE_PLAYBACK, // ADDR_PLAYBACK_3
+ };
+
+ private static final String[] DEFAULT_NAMES = {
+ "TV",
+ "Recorder_1",
+ "Recorder_2",
+ "Tuner_1",
+ "Playback_1",
+ "AudioSystem",
+ "Tuner_2",
+ "Tuner_3",
+ "Playback_2",
+ "Recorder_3",
+ "Tuner_4",
+ "Playback_3",
+ };
+
+ private HdmiCec() { } // Prevents instantiation.
+
+ /**
+ * Check if the given type is valid. A valid type is one of the actual
+ * logical device types defined in the standard ({@link #DEVICE_TV},
+ * {@link #DEVICE_PLAYBACK}, {@link #DEVICE_TUNER}, {@link #DEVICE_RECORDER},
+ * and {@link #DEVICE_AUDIO_SYSTEM}).
+ *
+ * @param type device type
+ * @return true if the given type is valid
+ */
+ public static boolean isValidType(int type) {
+ return (DEVICE_TV <= type && type <= DEVICE_AUDIO_SYSTEM)
+ && type != DEVICE_RESERVED;
+ }
+
+ /**
+ * Check if the given logical address is valid. A logical address is valid
+ * if it is one allocated for an actual device which allows communication
+ * with other logical devices.
+ *
+ * @param address logical address
+ * @return true if the given address is valid
+ */
+ public static boolean isValidAddress(int address) {
+ // TODO: We leave out the address 'free use(14)' for now. Check this later
+ // again to make sure it is a valid address for communication.
+ return (ADDR_TV <= address && address <= ADDR_PLAYBACK_3);
+ }
+
+ /**
+ * Return the device type for the given logical address.
+ *
+ * @param address logical address
+ * @return device type for the given logical address; DEVICE_INACTIVE
+ * if the address is not valid.
+ */
+ public static int getTypeFromAddress(int address) {
+ if (isValidAddress(address)) {
+ return ADDRESS_TO_TYPE[address];
+ }
+ return DEVICE_INACTIVE;
+ }
+
+ /**
+ * Return the default device name for a logical address. This is the name
+ * by which the logical device is known to others until a name is
+ * set explicitly using HdmiCecService.setOsdName.
+ *
+ * @param address logical address
+ * @return default device name; empty string if the address is not valid
+ */
+ public static String getDefaultDeviceName(int address) {
+ if (isValidAddress(address)) {
+ return DEFAULT_NAMES[address];
+ }
+ return "";
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
new file mode 100644
index 0000000..cd86cd8
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -0,0 +1,143 @@
+/*
+ * 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.hdmi;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import android.util.Log;
+
+/**
+ * HdmiCecClient is used to control HDMI-CEC logical device instance in the system.
+ * It is connected to actual hardware part via HdmiCecService. It provides with methods
+ * to send CEC messages to other device on the bus, and listener that allows to receive
+ * incoming messages to the device.
+ */
+public final class HdmiCecClient {
+ private static final String TAG = "HdmiCecClient";
+
+ private final IHdmiCecService mService;
+ private final IBinder mBinder;
+
+ /**
+ * Listener used by the client to get the incoming messages.
+ */
+ public static abstract class Listener {
+ /**
+ * Called when CEC message arrives. Override this method to receive the incoming
+ * CEC messages from other device on the bus.
+ *
+ * @param message {@link HdmiCecMessage} object
+ */
+ public void onMessageReceived(HdmiCecMessage message) { }
+
+ /**
+ * Called when hotplug event occurs. Override this method to receive the events.
+ *
+ * @param connected true if the cable is connected; otherwise false.
+ */
+ public void onCableStatusChanged(boolean connected) { }
+ }
+
+ // Private constructor.
+ private HdmiCecClient(IHdmiCecService service, IBinder b) {
+ mService = service;
+ mBinder = b;
+ }
+
+ // Factory method for HdmiCecClient.
+ // Declared package-private. Accessed by HdmiCecManager only.
+ static HdmiCecClient create(IHdmiCecService service, IBinder b) {
+ return new HdmiCecClient(service, b);
+ }
+
+ /**
+ * Send &lt;Active Source&gt; message.
+ */
+ public void sendActiveSource() {
+ try {
+ mService.sendActiveSource(mBinder);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendActiveSource threw exception ", e);
+ }
+ }
+
+ /**
+ * Send &lt;Inactive Source&gt; message.
+ */
+ public void sendInactiveSource() {
+ try {
+ mService.sendInactiveSource(mBinder);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendInactiveSource threw exception ", e);
+ }
+ }
+
+ /**
+ * Send &lt;Text View On&gt; message.
+ */
+ public void sendTextViewOn() {
+ try {
+ mService.sendTextViewOn(mBinder);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendTextViewOn threw exception ", e);
+ }
+ }
+
+ /**
+ * Send &lt;Image View On&gt; message.
+ */
+ public void sendImageViewOn() {
+ try {
+ mService.sendImageViewOn(mBinder);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendImageViewOn threw exception ", e);
+ }
+ }
+
+ /**
+ * Send &lt;Give Device Power Status&gt; message.
+ *
+ * @param address logical address of the device to send the message to, such as
+ * {@link HdmiCec#ADDR_TV}.
+ */
+ public void sendGiveDevicePowerStatus(int address) {
+ try {
+ mService.sendGiveDevicePowerStatus(mBinder, address);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+ }
+ }
+
+ /**
+ * Returns true if the TV or attached display is powered on.
+ * <p>
+ * The result of this method is only meaningful on playback devices (where the device
+ * type is {@link HdmiCec#DEVICE_PLAYBACK}).
+ * </p>
+ *
+ * @return true if TV is on; otherwise false.
+ */
+ public boolean isTvOn() {
+ try {
+ return mService.isTvOn(mBinder);
+ } catch (RemoteException e) {
+ Log.e(TAG, "isTvOn threw exception ", e);
+ }
+ return false;
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecManager.java b/core/java/android/hardware/hdmi/HdmiCecManager.java
new file mode 100644
index 0000000..10b058c
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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.hdmi;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * The HdmiCecManager class is used to provide an HdmiCecClient instance,
+ * get various information on HDMI ports configuration. It is connected to actual hardware
+ * via HdmiCecService.
+ */
+public final class HdmiCecManager {
+ private final IHdmiCecService mService;
+
+ /**
+ * @hide - hide this constructor because it has a parameter of type IHdmiCecService,
+ * which is a system private class. The right way to create an instance of this class
+ * is using the factory Context.getSystemService.
+ */
+ public HdmiCecManager(IHdmiCecService service) {
+ mService = service;
+ }
+
+ /**
+ * Provide the HdmiCecClient instance of the given type. It also registers the listener
+ * for client to get the events coming to the device.
+ *
+ * @param type type of the HDMI-CEC logical device
+ * @param listener listener to be called
+ * @return {@link HdmiCecClient} instance. {@code null} on failure.
+ */
+ public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) {
+ if (mService == null) {
+ return null;
+ }
+ try {
+ IBinder b = mService.allocateLogicalDevice(type, getListenerWrapper(listener));
+ return HdmiCecClient.create(mService, b);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ private IHdmiCecListener getListenerWrapper(final HdmiCecClient.Listener listener) {
+ // TODO: The message/events are not yet forwarded to client since it is not clearly
+ // defined as to how/who to handle them. Revisit it once the decision is
+ // made on what messages will have to reach the clients, what will be
+ // handled by service/manager.
+ return new IHdmiCecListener.Stub() {
+ @Override
+ public void onMessageReceived(HdmiCecMessage message) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onCableStatusChanged(boolean connected) {
+ // Do nothing.
+ }
+ };
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.aidl b/core/java/android/hardware/hdmi/HdmiCecMessage.aidl
new file mode 100644
index 0000000..6687ba4
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.hdmi;
+
+parcelable HdmiCecMessage;
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java
new file mode 100644
index 0000000..be94d97
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java
@@ -0,0 +1,145 @@
+/*
+ * 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.hdmi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * A class to encapsulate HDMI-CEC message used for the devices connected via
+ * HDMI cable to communicate with one another. A message is defined by its
+ * source and destination address, command (or opcode), and optional parameters.
+ */
+public final class HdmiCecMessage implements Parcelable {
+
+ private static final int MAX_MESSAGE_LENGTH = 16;
+
+ private final int mSource;
+ private final int mDestination;
+
+ private final int mOpcode;
+ private final byte[] mParams;
+
+ /**
+ * Constructor.
+ */
+ public HdmiCecMessage(int source, int destination, int opcode, byte[] params) {
+ mSource = source;
+ mDestination = destination;
+ mOpcode = opcode;
+ mParams = Arrays.copyOf(params, params.length);
+ }
+
+ /**
+ * Return the source address field of the message. It is the logical address
+ * of the device which generated the message.
+ *
+ * @return source address
+ */
+ public int getSource() {
+ return mSource;
+ }
+
+ /**
+ * Return the destination address field of the message. It is the logical address
+ * of the device to which the message is sent.
+ *
+ * @return destination address
+ */
+ public int getDestination() {
+ return mDestination;
+ }
+
+ /**
+ * Return the opcode field of the message. It is the type of the message that
+ * tells the destination device what to do.
+ *
+ * @return opcode
+ */
+ public int getOpcode() {
+ return mOpcode;
+ }
+
+ /**
+ * Return the parameter field of the message. The contents of parameter varies
+ * from opcode to opcode, and is used together with opcode to describe
+ * the action for the destination device to take.
+ *
+ * @return parameter
+ */
+ public byte[] getParams() {
+ return mParams;
+ }
+
+ /**
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSource);
+ dest.writeInt(mDestination);
+ dest.writeInt(mOpcode);
+ dest.writeInt(mParams.length);
+ dest.writeByteArray(mParams);
+ }
+
+ public static final Parcelable.Creator<HdmiCecMessage> CREATOR
+ = new Parcelable.Creator<HdmiCecMessage>() {
+ /**
+ * Rebuild a HdmiCecMessage previously stored with writeToParcel().
+ * @param p HdmiCecMessage object to read the Rating from
+ * @return a new HdmiCecMessage created from the data in the parcel
+ */
+ public HdmiCecMessage createFromParcel(Parcel p) {
+ int source = p.readInt();
+ int destination = p.readInt();
+ int opcode = p.readInt();
+ byte[] params = new byte[p.readInt()];
+ p.readByteArray(params);
+ return new HdmiCecMessage(source, destination, opcode, params);
+ }
+ public HdmiCecMessage[] newArray(int size) {
+ return new HdmiCecMessage[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ StringBuffer s = new StringBuffer();
+ s.append(String.format("src: %d dst: %d op: %2X params: ", mSource, mDestination, mOpcode));
+ for (byte data : mParams) {
+ s.append(String.format("%02X ", data));
+ }
+ return s.toString();
+ }
+}
+
diff --git a/core/java/android/hardware/hdmi/IHdmiCecListener.aidl b/core/java/android/hardware/hdmi/IHdmiCecListener.aidl
new file mode 100644
index 0000000..d281ce6
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiCecListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+
+/**
+ * Interface definition for HdmiCecService to do interprocess communcation.
+ *
+ * @hide
+ */
+oneway interface IHdmiCecListener {
+ void onMessageReceived(in HdmiCecMessage message);
+ void onCableStatusChanged(in boolean connected);
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
new file mode 100644
index 0000000..ecdd345
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiCecListener;
+import android.os.IBinder;
+
+/**
+ * Binder interface that components running in the appplication process
+ * will use to enable HDMI-CEC protocol exchange with other devices.
+ *
+ * @hide
+ */
+interface IHdmiCecService {
+ IBinder allocateLogicalDevice(int type, IHdmiCecListener listener);
+ void removeServiceListener(IBinder b, IHdmiCecListener listener);
+ void sendActiveSource(IBinder b);
+ void sendInactiveSource(IBinder b);
+ void sendImageViewOn(IBinder b);
+ void sendTextViewOn(IBinder b);
+ void sendGiveDevicePowerStatus(IBinder b, int address);
+ boolean isTvOn(IBinder b);
+ void sendMessage(IBinder b, in HdmiCecMessage message);
+}
+
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 9b6f82a..f1e7e98 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,6 +16,7 @@
package android.hardware.input;
+import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.IInputDevicesChangedListener;
import android.os.IBinder;
@@ -41,13 +42,13 @@ interface IInputManager {
// Keyboard layouts configuration.
KeyboardLayout[] getKeyboardLayouts();
KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
- String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor);
- void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ String getCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier);
+ void setCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor);
- String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor);
- void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ String[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
+ void addKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor);
- void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor);
// Registers an input devices changed listener.
diff --git a/core/java/android/hardware/input/InputDeviceIdentifier.aidl b/core/java/android/hardware/input/InputDeviceIdentifier.aidl
new file mode 100644
index 0000000..7234a91
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceIdentifier.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.hardware.input;
+
+parcelable InputDeviceIdentifier;
diff --git a/core/java/android/hardware/input/InputDeviceIdentifier.java b/core/java/android/hardware/input/InputDeviceIdentifier.java
new file mode 100644
index 0000000..5e832e3
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceIdentifier.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hardware.input;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Wrapper for passing identifying information for input devices.
+ *
+ * @hide
+ */
+public final class InputDeviceIdentifier implements Parcelable {
+ private final String mDescriptor;
+ private final int mVendorId;
+ private final int mProductId;
+
+ public InputDeviceIdentifier(String descriptor, int vendorId, int productId) {
+ this.mDescriptor = descriptor;
+ this.mVendorId = vendorId;
+ this.mProductId = productId;
+ }
+
+ private InputDeviceIdentifier(Parcel src) {
+ mDescriptor = src.readString();
+ mVendorId = src.readInt();
+ mProductId = src.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mDescriptor);
+ dest.writeInt(mVendorId);
+ dest.writeInt(mProductId);
+ }
+
+ public String getDescriptor() {
+ return mDescriptor;
+ }
+
+ public int getVendorId() {
+ return mVendorId;
+ }
+
+ public int getProductId() {
+ return mProductId;
+ }
+
+ public static final Parcelable.Creator<InputDeviceIdentifier> CREATOR =
+ new Parcelable.Creator<InputDeviceIdentifier>() {
+
+ @Override
+ public InputDeviceIdentifier createFromParcel(Parcel source) {
+ return new InputDeviceIdentifier(source);
+ }
+
+ @Override
+ public InputDeviceIdentifier[] newArray(int size) {
+ return new InputDeviceIdentifier[size];
+ }
+
+ };
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 30e69a6..a2aeafb 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -26,6 +26,8 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Vibrator;
@@ -373,20 +375,17 @@ public final class InputManager {
}
/**
- * Gets the current keyboard layout descriptor for the specified input device.
- *
- * @param inputDeviceDescriptor The input device descriptor.
- * @return The keyboard layout descriptor, or null if no keyboard layout has been set.
+ * Gets the current keyboard layout descriptor for the specified input
+ * device.
*
+ * @param identifier Identifier for the input device
+ * @return The keyboard layout descriptor, or null if no keyboard layout has
+ * been set.
* @hide
*/
- public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
- if (inputDeviceDescriptor == null) {
- throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
- }
-
+ public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
try {
- return mIm.getCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+ return mIm.getCurrentKeyboardLayoutForInputDevice(identifier);
} catch (RemoteException ex) {
Log.w(TAG, "Could not get current keyboard layout for input device.", ex);
return null;
@@ -394,28 +393,29 @@ public final class InputManager {
}
/**
- * Sets the current keyboard layout descriptor for the specified input device.
+ * Sets the current keyboard layout descriptor for the specified input
+ * device.
* <p>
- * This method may have the side-effect of causing the input device in question
- * to be reconfigured.
+ * This method may have the side-effect of causing the input device in
+ * question to be reconfigured.
* </p>
*
- * @param inputDeviceDescriptor The input device descriptor.
- * @param keyboardLayoutDescriptor The keyboard layout descriptor to use, must not be null.
- *
+ * @param identifier The identifier for the input device.
+ * @param keyboardLayoutDescriptor The keyboard layout descriptor to use,
+ * must not be null.
* @hide
*/
- public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
- if (inputDeviceDescriptor == null) {
- throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+ if (identifier == null) {
+ throw new IllegalArgumentException("identifier must not be null");
}
if (keyboardLayoutDescriptor == null) {
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
}
try {
- mIm.setCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor,
+ mIm.setCurrentKeyboardLayoutForInputDevice(identifier,
keyboardLayoutDescriptor);
} catch (RemoteException ex) {
Log.w(TAG, "Could not set current keyboard layout for input device.", ex);
@@ -423,20 +423,20 @@ public final class InputManager {
}
/**
- * Gets all keyboard layout descriptors that are enabled for the specified input device.
+ * Gets all keyboard layout descriptors that are enabled for the specified
+ * input device.
*
- * @param inputDeviceDescriptor The input device descriptor.
+ * @param identifier The identifier for the input device.
* @return The keyboard layout descriptors.
- *
* @hide
*/
- public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
- if (inputDeviceDescriptor == null) {
+ public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+ if (identifier == null) {
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
try {
- return mIm.getKeyboardLayoutsForInputDevice(inputDeviceDescriptor);
+ return mIm.getKeyboardLayoutsForInputDevice(identifier);
} catch (RemoteException ex) {
Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
return ArrayUtils.emptyArray(String.class);
@@ -446,18 +446,18 @@ public final class InputManager {
/**
* Adds the keyboard layout descriptor for the specified input device.
* <p>
- * This method may have the side-effect of causing the input device in question
- * to be reconfigured.
+ * This method may have the side-effect of causing the input device in
+ * question to be reconfigured.
* </p>
*
- * @param inputDeviceDescriptor The input device descriptor.
- * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to add.
- *
+ * @param identifier The identifier for the input device.
+ * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to
+ * add.
* @hide
*/
- public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
- if (inputDeviceDescriptor == null) {
+ if (identifier == null) {
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
if (keyboardLayoutDescriptor == null) {
@@ -465,7 +465,7 @@ public final class InputManager {
}
try {
- mIm.addKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+ mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
} catch (RemoteException ex) {
Log.w(TAG, "Could not add keyboard layout for input device.", ex);
}
@@ -474,18 +474,18 @@ public final class InputManager {
/**
* Removes the keyboard layout descriptor for the specified input device.
* <p>
- * This method may have the side-effect of causing the input device in question
- * to be reconfigured.
+ * This method may have the side-effect of causing the input device in
+ * question to be reconfigured.
* </p>
*
- * @param inputDeviceDescriptor The input device descriptor.
- * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to remove.
- *
+ * @param identifier The identifier for the input device.
+ * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to
+ * remove.
* @hide
*/
- public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+ public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
- if (inputDeviceDescriptor == null) {
+ if (identifier == null) {
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
if (keyboardLayoutDescriptor == null) {
@@ -493,7 +493,7 @@ public final class InputManager {
}
try {
- mIm.removeKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+ mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
} catch (RemoteException ex) {
Log.w(TAG, "Could not remove keyboard layout for input device.", ex);
}
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
new file mode 100644
index 0000000..6a392dd
--- /dev/null
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -0,0 +1,42 @@
+/*
+ * 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 {
+ public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+
+ /**
+ * Called by the display manager to set information about the displays as needed
+ * by the input system. The input system must copy this information to retain it.
+ */
+ public abstract void setDisplayViewports(DisplayViewport defaultViewport,
+ DisplayViewport externalTouchViewport);
+
+ /**
+ * Called by the power manager to tell the input manager whether it should start
+ * watching for wake events.
+ */
+ public abstract void setInteractive(boolean interactive);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c78a973..4eecfa9 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
@@ -395,6 +401,8 @@ public class ConnectivityManager {
private final IConnectivityManager mService;
+ private final String mPackageName;
+
/**
* Tests if a given integer represents a valid network type.
* @param networkType the type to be tested
@@ -444,6 +452,8 @@ public class ConnectivityManager {
return "WIFI_P2P";
case TYPE_MOBILE_IA:
return "MOBILE_IA";
+ case TYPE_PROXY:
+ return "PROXY";
default:
return Integer.toString(type);
}
@@ -802,7 +812,7 @@ public class ConnectivityManager {
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
byte[] address = hostAddress.getAddress();
try {
- return mService.requestRouteToHostAddress(networkType, address);
+ return mService.requestRouteToHostAddress(networkType, address, mPackageName);
} catch (RemoteException e) {
return false;
}
@@ -898,8 +908,9 @@ public class ConnectivityManager {
/**
* {@hide}
*/
- public ConnectivityManager(IConnectivityManager service) {
+ public ConnectivityManager(IConnectivityManager service, String packageName) {
mService = checkNotNull(service, "missing IConnectivityManager");
+ mPackageName = checkNotNull(packageName, "missing package name");
}
/** {@hide} */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index c1da2e3..4bca7fe 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -71,9 +71,9 @@ interface IConnectivityManager
int stopUsingNetworkFeature(int networkType, in String feature);
- boolean requestRouteToHost(int networkType, int hostAddress);
+ boolean requestRouteToHost(int networkType, int hostAddress, String packageName);
- boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
+ boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName);
boolean getMobileDataEnabled();
void setMobileDataEnabled(boolean enabled);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index c106514..21352bf 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -566,6 +566,17 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
return false;
}
+
+ public void setInternalDataEnable(boolean enabled) {
+ if (DBG) log("setInternalDataEnable: E enabled=" + enabled);
+ final AsyncChannel channel = mDataConnectionTrackerAc;
+ if (channel != null) {
+ channel.sendMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE,
+ enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
+ }
+ if (VDBG) log("setInternalDataEnable: X enabled=" + enabled);
+ }
+
@Override
public void setUserDataEnable(boolean enabled) {
if (DBG) log("setUserDataEnable: E enabled=" + enabled);
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/net/VpnService.java b/core/java/android/net/VpnService.java
index d7dc7f5..7385dff 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -151,9 +151,10 @@ public class VpnService extends Service {
}
/**
- * Protect a socket from VPN connections. The socket will be bound to the
- * current default network interface, so its traffic will not be forwarded
- * through VPN. This method is useful if some connections need to be kept
+ * Protect a socket from VPN connections. After protecting, data sent
+ * through this socket will go directly to the underlying network,
+ * so its traffic will not be forwarded through the VPN.
+ * This method is useful if some connections need to be kept
* outside of VPN. For example, a VPN tunnel should protect itself if its
* destination is covered by VPN routes. Otherwise its outgoing packets
* will be sent back to the VPN interface and cause an infinite loop. This
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 205a21d..6fdb0d0 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -18,8 +18,15 @@ package android.net.nsd;
import android.os.Parcelable;
import android.os.Parcel;
+import android.util.Log;
+import android.util.ArrayMap;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+
/**
* A class representing service information for network service discovery
@@ -27,11 +34,13 @@ import java.net.InetAddress;
*/
public final class NsdServiceInfo implements Parcelable {
+ private static final String TAG = "NsdServiceInfo";
+
private String mServiceName;
private String mServiceType;
- private DnsSdTxtRecord mTxtRecord;
+ private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<String, byte[]>();
private InetAddress mHost;
@@ -41,10 +50,9 @@ public final class NsdServiceInfo implements Parcelable {
}
/** @hide */
- public NsdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
+ public NsdServiceInfo(String sn, String rt) {
mServiceName = sn;
mServiceType = rt;
- mTxtRecord = tr;
}
/** Get the service name */
@@ -67,16 +75,6 @@ public final class NsdServiceInfo implements Parcelable {
mServiceType = s;
}
- /** @hide */
- public DnsSdTxtRecord getTxtRecord() {
- return mTxtRecord;
- }
-
- /** @hide */
- public void setTxtRecord(DnsSdTxtRecord t) {
- mTxtRecord = new DnsSdTxtRecord(t);
- }
-
/** Get the host address. The host address is valid for a resolved service. */
public InetAddress getHost() {
return mHost;
@@ -97,14 +95,134 @@ public final class NsdServiceInfo implements Parcelable {
mPort = p;
}
+ /** @hide */
+ public void setAttribute(String key, byte[] value) {
+ // Key must be printable US-ASCII, excluding =.
+ for (int i = 0; i < key.length(); ++i) {
+ char character = key.charAt(i);
+ if (character < 0x20 || character > 0x7E) {
+ throw new IllegalArgumentException("Key strings must be printable US-ASCII");
+ } else if (character == 0x3D) {
+ throw new IllegalArgumentException("Key strings must not include '='");
+ }
+ }
+
+ // Key length + value length must be < 255.
+ if (key.length() + (value == null ? 0 : value.length) >= 255) {
+ throw new IllegalArgumentException("Key length + value length must be < 255 bytes");
+ }
+
+ // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4.
+ if (key.length() > 9) {
+ Log.w(TAG, "Key lengths > 9 are discouraged: " + key);
+ }
+
+ // Check against total TXT record size limits.
+ // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2.
+ int txtRecordSize = getTxtRecordSize();
+ int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2;
+ if (futureSize > 1300) {
+ throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes");
+ } else if (futureSize > 400) {
+ Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur");
+ }
+
+ mTxtRecord.put(key, value);
+ }
+
+ /**
+ * Add a service attribute as a key/value pair.
+ *
+ * <p> Service attributes are included as DNS-SD TXT record pairs.
+ *
+ * <p> The key must be US-ASCII printable characters, excluding the '=' character. Values may
+ * be UTF-8 strings or null. The total length of key + value must be less than 255 bytes.
+ *
+ * <p> Keys should be short, ideally no more than 9 characters, and unique per instance of
+ * {@link NsdServiceInfo}. Calling {@link #setAttribute} twice with the same key will overwrite
+ * first value.
+ */
+ public void setAttribute(String key, String value) {
+ try {
+ setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("Value must be UTF-8");
+ }
+ }
+
+ /** Remove an attribute by key */
+ public void removeAttribute(String key) {
+ mTxtRecord.remove(key);
+ }
+
+ /**
+ * Retrive attributes as a map of String keys to byte[] values.
+ *
+ * <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and
+ * {@link #removeAttribute}.
+ */
+ public Map<String, byte[]> getAttributes() {
+ return Collections.unmodifiableMap(mTxtRecord);
+ }
+
+ private int getTxtRecordSize() {
+ int txtRecordSize = 0;
+ for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+ txtRecordSize += 2; // One for the length byte, one for the = between key and value.
+ txtRecordSize += entry.getKey().length();
+ byte[] value = entry.getValue();
+ txtRecordSize += value == null ? 0 : value.length;
+ }
+ return txtRecordSize;
+ }
+
+ /** @hide */
+ public byte[] getTxtRecord() {
+ int txtRecordSize = getTxtRecordSize();
+ if (txtRecordSize == 0) {
+ return null;
+ }
+
+ byte[] txtRecord = new byte[txtRecordSize];
+ int ptr = 0;
+ for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+ String key = entry.getKey();
+ byte[] value = entry.getValue();
+
+ // One byte to record the length of this key/value pair.
+ txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1);
+
+ // The key, in US-ASCII.
+ // Note: use the StandardCharsets const here because it doesn't raise exceptions and we
+ // already know the key is ASCII at this point.
+ System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr,
+ key.length());
+ ptr += key.length();
+
+ // US-ASCII '=' character.
+ txtRecord[ptr++] = (byte)'=';
+
+ // The value, as any raw bytes.
+ if (value != null) {
+ System.arraycopy(value, 0, txtRecord, ptr, value.length);
+ ptr += value.length;
+ }
+ }
+ return txtRecord;
+ }
+
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("name: ").append(mServiceName).
- append("type: ").append(mServiceType).
- append("host: ").append(mHost).
- append("port: ").append(mPort).
- append("txtRecord: ").append(mTxtRecord);
+ sb.append("name: ").append(mServiceName)
+ .append(", type: ").append(mServiceType)
+ .append(", host: ").append(mHost)
+ .append(", port: ").append(mPort);
+
+ byte[] txtRecord = getTxtRecord();
+ if (txtRecord != null) {
+ sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
+ }
return sb.toString();
}
@@ -117,14 +235,27 @@ public final class NsdServiceInfo implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mServiceName);
dest.writeString(mServiceType);
- dest.writeParcelable(mTxtRecord, flags);
if (mHost != null) {
- dest.writeByte((byte)1);
+ dest.writeInt(1);
dest.writeByteArray(mHost.getAddress());
} else {
- dest.writeByte((byte)0);
+ dest.writeInt(0);
}
dest.writeInt(mPort);
+
+ // TXT record key/value pairs.
+ dest.writeInt(mTxtRecord.size());
+ for (String key : mTxtRecord.keySet()) {
+ byte[] value = mTxtRecord.get(key);
+ if (value != null) {
+ dest.writeInt(1);
+ dest.writeInt(value.length);
+ dest.writeByteArray(value);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeString(key);
+ }
}
/** Implement the Parcelable interface */
@@ -134,15 +265,26 @@ public final class NsdServiceInfo implements Parcelable {
NsdServiceInfo info = new NsdServiceInfo();
info.mServiceName = in.readString();
info.mServiceType = in.readString();
- info.mTxtRecord = in.readParcelable(null);
- if (in.readByte() == 1) {
+ if (in.readInt() == 1) {
try {
info.mHost = InetAddress.getByAddress(in.createByteArray());
} catch (java.net.UnknownHostException e) {}
}
info.mPort = in.readInt();
+
+ // TXT record key/value pairs.
+ int recordCount = in.readInt();
+ for (int i = 0; i < recordCount; ++i) {
+ byte[] valueArray = null;
+ if (in.readInt() == 1) {
+ int valueLength = in.readInt();
+ valueArray = new byte[valueLength];
+ in.readByteArray(valueArray);
+ }
+ info.mTxtRecord.put(in.readString(), valueArray);
+ }
return info;
}
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 c3313c5..fae2d52 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. */
@@ -474,6 +474,11 @@ public class Build {
* </ul>
*/
public static final int KITKAT = 19;
+
+ /**
+ * Android 4.5: KitKat for watches, snacks on the run.
+ */
+ public static final int KITKAT_WATCH = CUR_DEVELOPMENT; // STOPSHIP: update API level
}
/** The type of build, like "user" or "eng". */
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/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 21b8ae5..f65b6ba 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -420,7 +420,7 @@ interface INetworkManagementService
/**
* Clear a user range from being associated with an interface.
*/
- void clearDnsInterfaceForUidRange(int uid_start, int uid_end);
+ void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end);
/**
* Clear the mappings from pid to Dns interface and from uid range to Dns interface.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 56176a4..92af1a5 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -37,8 +37,8 @@ interface IPowerManager
void wakeUp(long time);
void goToSleep(long time, int reason);
void nap(long time);
+ boolean isInteractive();
- boolean isScreenOn();
void reboot(boolean confirm, String reason, boolean wait);
void shutdown(boolean confirm, boolean wait);
void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 5e0d489..646bfef 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.");
@@ -569,21 +582,64 @@ public final class PowerManager {
}
/**
- * Returns whether the screen is currently on.
+ * Returns true if the device is in an interactive state.
* <p>
- * Only indicates whether the screen is on. The screen could be either bright or dim.
+ * For historical reasons, the name of this method refers to the power state of
+ * the screen but it actually describes the overall interactive state of
+ * the device. This method has been replaced by {@link #isInteractive}.
* </p><p>
- * {@samplecode
- * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- * boolean isScreenOn = pm.isScreenOn();
- * }
+ * The value returned by this method only indicates whether the device is
+ * in an interactive state which may have nothing to do with the screen being
+ * on or off. To determine the actual state of the screen,
+ * use {@link android.view.Display#getState}.
* </p>
*
- * @return whether the screen is on (bright or dim).
+ * @return True if the device is in an interactive state.
+ *
+ * @deprecated Use {@link #isInteractive} instead.
*/
+ @Deprecated
public boolean isScreenOn() {
+ return isInteractive();
+ }
+
+ /**
+ * Returns true if the device is in an interactive state.
+ * <p>
+ * When this method returns true, the device is awake and ready to interact
+ * with the user (although this is not a guarantee that the user is actively
+ * interacting with the device just this moment). The main screen is usually
+ * turned on while in this state. Certain features, such as the proximity
+ * sensor, may temporarily turn off the screen while still leaving the device in an
+ * interactive state. Note in particular that the device is still considered
+ * to be interactive while dreaming (since dreams can be interactive) but not
+ * when it is dozing or asleep.
+ * </p><p>
+ * When this method returns false, the device is dozing or asleep and must
+ * be awoken before it will become ready to interact with the user again. The
+ * main screen is usually turned off while in this state. Certain features,
+ * such as "ambient mode" may cause the main screen to remain on (albeit in a
+ * low power state) to display system-provided content while the device dozes.
+ * </p><p>
+ * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
+ * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
+ * whenever the interactive state of the device changes. For historical reasons,
+ * the names of these broadcasts refer to the power state of the screen
+ * but they are actually sent in response to changes in the overall interactive
+ * state of the device, as described by this method.
+ * </p><p>
+ * Services may use the non-interactive state as a hint to conserve power
+ * since the user is not present.
+ * </p>
+ *
+ * @return True if the device is in an interactive state.
+ *
+ * @see android.content.Intent#ACTION_SCREEN_ON
+ * @see android.content.Intent#ACTION_SCREEN_OFF
+ */
+ public boolean isInteractive() {
try {
- return mService.isScreenOn();
+ return mService.isInteractive();
} catch (RemoteException e) {
return false;
}
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 96f42cc..995e396 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -982,19 +982,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/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b692ffd..f671ed9 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -338,11 +338,11 @@ public class RecoverySystem {
}
/**
- * Reboots the device and wipes the user data partition. This is
- * sometimes called a "factory reset", which is something of a
- * misnomer because the system partition is not restored to its
- * factory state.
- * Requires the {@link android.Manifest.permission#REBOOT} permission.
+ * Reboots the device and wipes the user data and cache
+ * partitions. This is sometimes called a "factory reset", which
+ * is something of a misnomer because the system partition is not
+ * restored to its factory state. Requires the
+ * {@link android.Manifest.permission#REBOOT} permission.
*
* @param context the Context to use
*
@@ -350,6 +350,28 @@ public class RecoverySystem {
* fails, or if the reboot itself fails.
*/
public static void rebootWipeUserData(Context context) throws IOException {
+ rebootWipeUserData(context, false);
+ }
+
+ /**
+ * Reboots the device and wipes the user data and cache
+ * partitions. This is sometimes called a "factory reset", which
+ * is something of a misnomer because the system partition is not
+ * restored to its factory state. Requires the
+ * {@link android.Manifest.permission#REBOOT} permission.
+ *
+ * @param context the Context to use
+ * @param shutdown if true, the device will be powered down after
+ * the wipe completes, rather than being rebooted
+ * back to the regular system.
+ *
+ * @throws IOException if writing the recovery command file
+ * fails, or if the reboot itself fails.
+ *
+ * @hide
+ */
+ public static void rebootWipeUserData(Context context, boolean shutdown)
+ throws IOException {
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
@@ -365,7 +387,13 @@ public class RecoverySystem {
// Block until the ordered broadcast has completed.
condition.block();
- bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString());
+ String shutdownArg = "";
+ if (shutdown) {
+ shutdownArg = "--shutdown_after\n";
+ }
+
+ bootCommand(context, shutdownArg + "--wipe_data\n--locale=" +
+ Locale.getDefault().toString());
}
/**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index d794ca6..ea71ad8 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1449,7 +1449,11 @@ public final class StrictMode {
if (policy.classInstanceLimit.size() == 0) {
return;
}
- Runtime.getRuntime().gc();
+
+ System.gc();
+ System.runFinalization();
+ System.gc();
+
// Note: classInstanceLimit is immutable, so this is lock-free
for (Map.Entry<Class, Integer> entry : policy.classInstanceLimit.entrySet()) {
Class klass = entry.getKey();
@@ -2005,7 +2009,10 @@ public final class StrictMode {
// noticeably less responsive during orientation changes when activities are
// being restarted. Granted, it is only a problem when StrictMode is enabled
// but it is annoying.
- Runtime.getRuntime().gc();
+
+ System.gc();
+ System.runFinalization();
+ System.gc();
long instances = VMDebug.countInstancesOfClass(klass, false);
if (instances > limit) {
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 6650fca..5d55143 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -21,11 +21,11 @@ import android.content.Context;
/**
* Class that operates the vibrator on the device.
* <p>
- * If your process exits, any vibration you started with will stop.
+ * If your process exits, any vibration you started will stop.
* </p>
*
* To obtain an instance of the system vibrator, call
- * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument.
+ * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument.
*/
public abstract class Vibrator {
/**
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/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index b615600..806a89d 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -475,6 +475,12 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @param colorModes The color mode bit mask.
* @param defaultColorMode The default color mode.
* @return This builder.
+ * <p>
+ * <strong>Note:</strong> On platform version 19 (Kitkat) specifying
+ * only PrintAttributes#COLOR_MODE_MONOCHROME leads to a print spooler
+ * crash. Hence, you should declare either both color modes or
+ * PrintAttributes#COLOR_MODE_COLOR.
+ * </p>
*
* @throws IllegalArgumentException If color modes contains an invalid
* mode bit or if the default color mode is invalid.
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/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f69cad0..457afcc 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -109,14 +109,18 @@ public final class MediaStore {
* An intent to perform a search for music media and automatically play content from the
* result when possible. This can be fired, for example, by the result of a voice recognition
* command to listen to music.
- * <p>
- * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string
- * that can contain any type of unstructured music search, like the name of an artist,
- * an album, a song, a genre, or any combination of these.
- * <p>
- * Because this intent includes an open-ended unstructured search string, it makes the most
- * sense for apps that can support large-scale search of music, such as services connected
- * to an online database of music which can be streamed and played on the device.
+ * <p>This intent always includes the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}
+ * and {@link android.app.SearchManager#QUERY} extras. The
+ * {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra determines the search mode, and
+ * the value of the {@link android.app.SearchManager#QUERY} extra depends on the search mode.
+ * For more information about the search modes for this intent, see
+ * <a href="{@docRoot}guide/components/intents-common.html#PlaySearch">Play music based
+ * on a search query</a> in <a href="{@docRoot}guide/components/intents-common.html">Common
+ * Intents</a>.</p>
+ *
+ * <p>This intent makes the most sense for apps that can support large-scale search of music,
+ * such as services connected to an online database of music which can be streamed and played
+ * on the device.</p>
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 04f3f0a..3810eb3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5140,6 +5140,12 @@ public final class Settings {
public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule";
/**
+ * Used to select TCP's default initial receiver window size in segments - defaults to a build config value
+ * @hide
+ */
+ public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd";
+
+ /**
* Used to disable Tethering on a device - defaults to true
* @hide
*/
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..2303d65 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 mInteractive;
private boolean mLowProfile = true;
- private boolean mFullscreen = false;
+ private boolean mFullscreen;
private boolean mScreenBright = true;
+ private boolean mStarted;
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) {
@@ -325,7 +340,7 @@ public class DreamService extends Service implements Window.Callback {
* @return The current window manager, or null if the dream is not started.
*/
public WindowManager getWindowManager() {
- return mWindowManager;
+ return mWindow != null ? mWindow.getWindowManager() : null;
}
/**
@@ -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 && mWindowToken != 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,41 +695,31 @@ 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.
*
* Must run on mHandler.
*/
private final void detach() {
- if (mWindow == null) {
- // already detached!
- return;
- }
-
- try {
+ if (mStarted) {
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ mStarted = false;
onDreamingStopped();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStopped()", t);
- // we were going to stop anyway
}
- if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
- try {
+ if (mWindow != null) {
// force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
+ if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
+ mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
+ mWindow = null;
+ }
+
+ if (mWindowToken != null) {
// 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);
+ mWindowToken = null;
}
-
- mWindow = null;
- mWindowToken = null;
}
/**
@@ -601,18 +729,26 @@ 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;
+ mCanDoze = canDoze;
+
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
@@ -635,33 +771,35 @@ public class DreamService extends Service implements Window.Callback {
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
-
- if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
-
mWindow.setWindowManager(null, windowToken, "dream", true);
- mWindowManager = mWindow.getWindowManager();
- if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
+
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();
+ } catch (WindowManager.BadTokenException ex) {
+ // This can happen because the dream manager service will remove the token
+ // immediately without necessarily waiting for the dream to start.
+ // We should receive a finish message soon.
+ Slog.i(TAG, "attach() called after window token already removed, dream will "
+ + "finish soon");
+ mWindow = null;
return;
}
- // start it up
+ // We need to defer calling onDreamingStarted until after onWindowAttached,
+ // which is posted to the handler by addView, so we post onDreamingStarted
+ // to the handler also. Need to watch out here in case detach occurs before
+ // this callback is invoked.
mHandler.post(new Runnable() {
@Override
public void run() {
- try {
+ if (mWindow != null) {
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ mStarted = true;
onDreamingStarted();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStarted()", t);
- safelyFinish();
}
}
});
@@ -669,13 +807,8 @@ public class DreamService extends Service implements Window.Callback {
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 +818,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
}
}
@@ -710,7 +845,7 @@ public class DreamService extends Service implements Window.Callback {
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.flags = applyFlags(lp.flags, flags, mask);
mWindow.setAttributes(lp);
- mWindowManager.updateViewLayout(mWindow.getDecorView(), lp);
+ mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
}
}
@@ -732,32 +867,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/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 425fdc1..d4b29d8 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -21,6 +21,7 @@ import android.service.notification.StatusBarNotification;
/** @hide */
oneway interface INotificationListener
{
+ void onListenerConnected(in String[] notificationKeys);
void onNotificationPosted(in StatusBarNotification notification);
void onNotificationRemoved(in StatusBarNotification notification);
} \ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 2e0e59b..8eaee29 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -83,6 +83,17 @@ public abstract class NotificationListenerService extends Service {
*/
public abstract void onNotificationRemoved(StatusBarNotification sbn);
+ /**
+ * Implement this method to learn about when the listener is enabled and connected to
+ * the notification manager. You are safe to call {@link #getActiveNotifications(String[])
+ * at this time.
+ *
+ * @param notificationKeys The notification keys for all currently posted notifications.
+ */
+ public void onListenerConnected(String[] notificationKeys) {
+ // optional
+ }
+
private final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
@@ -112,6 +123,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,8 +143,23 @@ public abstract class NotificationListenerService extends Service {
* {@see #cancelNotification(String, String, int)}
*/
public final void cancelAllNotifications() {
+ cancelNotifications(null /*all*/);
+ }
+
+ /**
+ * Inform the notification manager about dismissal of specific notifications.
+ * <p>
+ * Use this if your listener has a user interface that allows the user to dismiss
+ * multiple notifications at once.
+ *
+ * @param keys Notifications to dismiss, or {@code null} to dismiss all.
+ *
+ * {@see #cancelNotification(String, String, int)}
+ */
+ public final void cancelNotifications(String[] keys) {
+ if (!isBound()) return;
try {
- getNotificationInterface().cancelAllNotificationsFromListener(mWrapper);
+ getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -140,13 +167,25 @@ public abstract class NotificationListenerService extends Service {
/**
* Request the list of outstanding notifications (that is, those that are visible to the
- * current user). Useful when starting up and you don't know what's already been posted.
+ * current user). Useful when you don't know what's already been posted.
*
* @return An array of active notifications.
*/
public StatusBarNotification[] getActiveNotifications() {
+ return getActiveNotifications(null /*all*/);
+ }
+
+ /**
+ * Request the list of outstanding notifications (that is, those that are visible to the
+ * current user). Useful when you don't know what's already been posted.
+ *
+ * @param keys A specific list of notification keys, or {@code null} for all.
+ * @return An array of active notifications.
+ */
+ public StatusBarNotification[] getActiveNotifications(String[] keys) {
+ if (!isBound()) return null;
try {
- return getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
+ return getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -161,6 +200,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) {
@@ -178,5 +225,13 @@ public abstract class NotificationListenerService extends Service {
Log.w(TAG, "Error running onNotificationRemoved", t);
}
}
+ @Override
+ public void onListenerConnected(String[] notificationKeys) {
+ try {
+ NotificationListenerService.this.onListenerConnected(notificationKeys);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onListenerConnected", t);
+ }
+ }
}
}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index b5b9e14..96dd143d 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -29,6 +29,7 @@ public class StatusBarNotification implements Parcelable {
private final String pkg;
private final int id;
private final String tag;
+ private final String key;
private final int uid;
private final String basePkg;
@@ -70,6 +71,7 @@ public class StatusBarNotification implements Parcelable {
this.notification.setUser(user);
this.postTime = postTime;
+ this.key = key();
}
public StatusBarNotification(Parcel in) {
@@ -88,6 +90,11 @@ public class StatusBarNotification implements Parcelable {
this.user = UserHandle.readFromParcel(in);
this.notification.setUser(this.user);
this.postTime = in.readLong();
+ this.key = key();
+ }
+
+ private String key() {
+ return pkg + '|' + basePkg + '|' + id + '|' + tag + '|' + uid;
}
public void writeToParcel(Parcel out, int flags) {
@@ -148,9 +155,9 @@ public class StatusBarNotification implements Parcelable {
@Override
public String toString() {
return String.format(
- "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+ "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
this.pkg, this.user, this.id, this.tag,
- this.score, this.notification);
+ this.score, this.key, this.notification);
}
/** Convenience method to check the notification's flags for
@@ -230,4 +237,11 @@ public class StatusBarNotification implements Parcelable {
public int getScore() {
return score;
}
+
+ /**
+ * A unique instance key for this notification record.
+ */
+ public String getKey() {
+ return key;
+ }
}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 94aedbd..91c3799 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -409,7 +409,7 @@ public class SpeechRecognizer {
* Internal wrapper of IRecognitionListener which will propagate the results to
* RecognitionListener
*/
- private class InternalListener extends IRecognitionListener.Stub {
+ private static class InternalListener extends IRecognitionListener.Stub {
private RecognitionListener mInternalListener;
private final static int MSG_BEGINNING_OF_SPEECH = 1;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e7d6fda..1f32d4d 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -654,7 +654,7 @@ public class StaticLayout extends Layout {
int extra;
- if (needMultiply) {
+ if (needMultiply && end != bufEnd) {
double ex = (below - above) * (spacingmult - 1) + spacingadd;
if (ex >= 0) {
extra = (int)(ex + EXTRA_ROUNDING);
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/Display.java b/core/java/android/view/Display.java
index 7d310a2..c4494f4 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -204,6 +204,36 @@ public final class Display {
public static final int TYPE_VIRTUAL = 5;
/**
+ * Display state: The display state is unknown.
+ *
+ * @see #getState
+ */
+ public static final int STATE_UNKNOWN = 0;
+
+ /**
+ * Display state: The display is off.
+ *
+ * @see #getState
+ */
+ public static final int STATE_OFF = 1;
+
+ /**
+ * Display state: The display is on.
+ *
+ * @see #getState
+ */
+ public static final int STATE_ON = 2;
+
+ /**
+ * Display state: The display is dozing in a low-power state; it may be showing
+ * system-provided content while the device is in a non-interactive state.
+ *
+ * @see #getState
+ * @see android.os.PowerManager#isInteractive
+ */
+ public static final int STATE_DOZING = 3;
+
+ /**
* Internal method to create a display.
* Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
* or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -628,6 +658,19 @@ public final class Display {
}
/**
+ * Gets the state of the display, such as whether it is on or off.
+ *
+ * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
+ * {@link #STATE_DOZING}, or {@link #STATE_UNKNOWN}.
+ */
+ public int getState() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN;
+ }
+ }
+
+ /**
* Returns true if the specified UID has access to this display.
* @hide
*/
@@ -718,5 +761,22 @@ public final class Display {
return Integer.toString(type);
}
}
-}
+ /**
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_UNKNOWN:
+ return "UNKNOWN";
+ case STATE_OFF:
+ return "OFF";
+ case STATE_ON:
+ return "ON";
+ case STATE_DOZING:
+ return "DOZING";
+ default:
+ return Integer.toString(state);
+ }
+ }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 8944207..5f840d3 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,11 @@ public final class DisplayInfo implements Parcelable {
public float physicalYDpi;
/**
+ * The state of the display, such as {@link android.view.Display#STATE_ON}.
+ */
+ public int state;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -248,6 +253,7 @@ public final class DisplayInfo implements Parcelable {
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
+ && state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
}
@@ -280,6 +286,7 @@ public final class DisplayInfo implements Parcelable {
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
+ state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
}
@@ -307,6 +314,7 @@ public final class DisplayInfo implements Parcelable {
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
+ state = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString();
}
@@ -335,6 +343,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
+ dest.writeInt(state);
dest.writeInt(ownerUid);
dest.writeString(ownerPackageName);
}
@@ -431,7 +440,7 @@ public final class DisplayInfo implements Parcelable {
sb.append(smallestNominalAppHeight);
sb.append(", ");
sb.append(refreshRate);
- sb.append(" fps, rotation");
+ sb.append(" fps, rotation ");
sb.append(rotation);
sb.append(", density ");
sb.append(logicalDensityDpi);
@@ -446,6 +455,8 @@ public final class DisplayInfo implements Parcelable {
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", state ");
+ sb.append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8ec07ef..3670eed 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -50,7 +50,6 @@ oneway interface IWindow {
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
- void dispatchScreenState(boolean on);
/**
* Tell the window that it is either gaining or losing focus. Keep it up
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index e829116..ae5f37e 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -17,6 +17,7 @@
package android.view;
import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -49,6 +50,7 @@ public final class InputDevice implements Parcelable {
private final int mVendorId;
private final int mProductId;
private final String mDescriptor;
+ private final InputDeviceIdentifier mIdentifier;
private final boolean mIsExternal;
private final int mSources;
private final int mKeyboardType;
@@ -61,7 +63,7 @@ public final class InputDevice implements Parcelable {
/**
* A mask for input source classes.
- *
+ *
* Each distinct input source constant has one or more input source class bits set to
* specify the desired interpretation for its input events.
*/
@@ -77,46 +79,46 @@ public final class InputDevice implements Parcelable {
/**
* The input source has buttons or keys.
* Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
- *
+ *
* A {@link KeyEvent} should be interpreted as a button or key press.
- *
+ *
* Use {@link #getKeyCharacterMap} to query the device's button and key mappings.
*/
public static final int SOURCE_CLASS_BUTTON = 0x00000001;
-
+
/**
* The input source is a pointing device associated with a display.
* Examples: {@link #SOURCE_TOUCHSCREEN}, {@link #SOURCE_MOUSE}.
- *
+ *
* A {@link MotionEvent} should be interpreted as absolute coordinates in
* display units according to the {@link View} hierarchy. Pointer down/up indicated when
* the finger touches the display or when the selection button is pressed/released.
- *
+ *
* Use {@link #getMotionRange} to query the range of the pointing device. Some devices permit
* touches outside the display area so the effective range may be somewhat smaller or larger
* than the actual display size.
*/
public static final int SOURCE_CLASS_POINTER = 0x00000002;
-
+
/**
* The input source is a trackball navigation device.
* Examples: {@link #SOURCE_TRACKBALL}.
- *
+ *
* A {@link MotionEvent} should be interpreted as relative movements in device-specific
* units used for navigation purposes. Pointer down/up indicates when the selection button
* is pressed/released.
- *
+ *
* Use {@link #getMotionRange} to query the range of motion.
*/
public static final int SOURCE_CLASS_TRACKBALL = 0x00000004;
-
+
/**
* The input source is an absolute positioning device not associated with a display
* (unlike {@link #SOURCE_CLASS_POINTER}).
- *
+ *
* A {@link MotionEvent} should be interpreted as absolute coordinates in
* device-specific surface units.
- *
+ *
* Use {@link #getMotionRange} to query the range of positions.
*/
public static final int SOURCE_CLASS_POSITION = 0x00000008;
@@ -134,7 +136,7 @@ public final class InputDevice implements Parcelable {
* The input source is unknown.
*/
public static final int SOURCE_UNKNOWN = 0x00000000;
-
+
/**
* The input source is a keyboard.
*
@@ -145,10 +147,10 @@ public final class InputDevice implements Parcelable {
* @see #SOURCE_CLASS_BUTTON
*/
public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;
-
+
/**
* The input source is a DPad.
- *
+ *
* @see #SOURCE_CLASS_BUTTON
*/
public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;
@@ -163,16 +165,16 @@ public final class InputDevice implements Parcelable {
/**
* The input source is a touch screen pointing device.
- *
+ *
* @see #SOURCE_CLASS_POINTER
*/
public static final int SOURCE_TOUCHSCREEN = 0x00001000 | SOURCE_CLASS_POINTER;
-
+
/**
* The input source is a mouse pointing device.
* This code is also used for other mouse-like pointing devices such as trackpads
* and trackpoints.
- *
+ *
* @see #SOURCE_CLASS_POINTER
*/
public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER;
@@ -199,15 +201,15 @@ public final class InputDevice implements Parcelable {
/**
* The input source is a trackball.
- *
+ *
* @see #SOURCE_CLASS_TRACKBALL
*/
public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;
-
+
/**
* The input source is a touch pad or digitizer tablet that is not
* associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
- *
+ *
* @see #SOURCE_CLASS_POSITION
*/
public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
@@ -239,7 +241,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_X}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_X} instead.
*/
@@ -248,7 +250,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_Y}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_Y} instead.
*/
@@ -257,7 +259,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_PRESSURE}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_PRESSURE} instead.
*/
@@ -266,7 +268,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_SIZE}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_SIZE} instead.
*/
@@ -275,7 +277,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOUCH_MAJOR}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_TOUCH_MAJOR} instead.
*/
@@ -284,7 +286,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOUCH_MINOR}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_TOUCH_MINOR} instead.
*/
@@ -293,7 +295,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOOL_MAJOR}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_TOOL_MAJOR} instead.
*/
@@ -302,7 +304,7 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOOL_MINOR}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_TOOL_MINOR} instead.
*/
@@ -311,24 +313,24 @@ public final class InputDevice implements Parcelable {
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_ORIENTATION}.
- *
+ *
* @see #getMotionRange
* @deprecated Use {@link MotionEvent#AXIS_ORIENTATION} instead.
*/
@Deprecated
public static final int MOTION_RANGE_ORIENTATION = MotionEvent.AXIS_ORIENTATION;
-
+
/**
* There is no keyboard.
*/
public static final int KEYBOARD_TYPE_NONE = 0;
-
+
/**
* The keyboard is not fully alphabetic. It may be a numeric keypad or an assortment
* of buttons that are not mapped as alphabetic keys suitable for text input.
*/
public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1;
-
+
/**
* The keyboard supports a complement of alphabetic keys.
*/
@@ -361,6 +363,7 @@ public final class InputDevice implements Parcelable {
mKeyCharacterMap = keyCharacterMap;
mHasVibrator = hasVibrator;
mHasButtonUnderPad = hasButtonUnderPad;
+ mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
}
private InputDevice(Parcel in) {
@@ -377,6 +380,7 @@ public final class InputDevice implements Parcelable {
mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
mHasVibrator = in.readInt() != 0;
mHasButtonUnderPad = in.readInt() != 0;
+ mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);
for (;;) {
int axis = in.readInt();
@@ -396,7 +400,7 @@ public final class InputDevice implements Parcelable {
public static InputDevice getDevice(int id) {
return InputManager.getInstance().getInputDevice(id);
}
-
+
/**
* Gets the ids of all input devices in the system.
* @return The input device ids.
@@ -441,6 +445,18 @@ public final class InputDevice implements Parcelable {
}
/**
+ * The set of identifying information for type of input device. This
+ * information can be used by the system to configure appropriate settings
+ * for the device.
+ *
+ * @return The identifier object for this device
+ * @hide
+ */
+ public InputDeviceIdentifier getIdentifier() {
+ return mIdentifier;
+ }
+
+ /**
* Gets a generation number for this input device.
* The generation number is incremented whenever the device is reconfigured and its
* properties may have changed.
@@ -553,7 +569,7 @@ public final class InputDevice implements Parcelable {
public String getName() {
return mName;
}
-
+
/**
* Gets the input sources supported by this input device as a combined bitfield.
* @return The supported input sources.
@@ -561,7 +577,19 @@ public final class InputDevice implements Parcelable {
public int getSources() {
return mSources;
}
-
+
+ /**
+ * Determines whether the input device supports the given source or sources.
+ *
+ * @param source The input source or sources to check against. This can be a generic device
+ * type such as {@link InputDevice#SOURCE_MOUSE}, a more generic device class, such as
+ * {@link InputDevice#SOURCE_CLASS_POINTER}, or a combination of sources bitwise ORed together.
+ * @return Whether the device can produce all of the given sources.
+ */
+ public boolean supportsSource(int source) {
+ return (mSources & source) == source;
+ }
+
/**
* Gets the keyboard type.
* @return The keyboard type.
@@ -569,7 +597,7 @@ public final class InputDevice implements Parcelable {
public int getKeyboardType() {
return mKeyboardType;
}
-
+
/**
* Gets the key character map associated with this input device.
* @return The key character map.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 5a5fc10..7b389c0 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -629,11 +629,19 @@ public class KeyEvent extends InputEvent implements Parcelable {
/** Key code constant: Brightness Up key.
* Adjusts the screen brightness up. */
public static final int KEYCODE_BRIGHTNESS_UP = 221;
- /** Key code constant: Audio Track key
+ /** Key code constant: Audio Track key.
* Switches the audio tracks. */
public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222;
+ /** Key code constant: Sleep key.
+ * Puts the device to sleep. Behaves somewhat like {@link #KEYCODE_POWER} but it
+ * has no effect if the device is already asleep. */
+ public static final int KEYCODE_SLEEP = 223;
+ /** Key code constant: Wakeup key.
+ * Wakes up the device. Behaves somewhat like {@link #KEYCODE_POWER} but it
+ * has no effect if the device is already awake. */
+ public static final int KEYCODE_WAKEUP = 224;
- private static final int LAST_KEYCODE = KEYCODE_MEDIA_AUDIO_TRACK;
+ private static final int LAST_KEYCODE = KEYCODE_WAKEUP;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -878,6 +886,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
names.append(KEYCODE_BRIGHTNESS_DOWN, "KEYCODE_BRIGHTNESS_DOWN");
names.append(KEYCODE_BRIGHTNESS_UP, "KEYCODE_BRIGHTNESS_UP");
names.append(KEYCODE_MEDIA_AUDIO_TRACK, "KEYCODE_MEDIA_AUDIO_TRACK");
+ names.append(KEYCODE_SLEEP, "KEYCODE_SLEEP");
+ names.append(KEYCODE_WAKEUP, "KEYCODE_WAKEUP");
};
// Symbolic names of all metakeys in bit order from least significant to most significant.
@@ -1157,9 +1167,13 @@ public class KeyEvent extends InputEvent implements Parcelable {
/**
* This mask is set if the device woke because of this key event.
+ *
+ * @deprecated This flag will never be set by the system since the system
+ * consumes all wake keys itself.
*/
+ @Deprecated
public static final int FLAG_WOKE_HERE = 0x1;
-
+
/**
* This mask is set if the key event was generated by a software keyboard.
*/
@@ -1837,13 +1851,32 @@ public class KeyEvent extends InputEvent implements Parcelable {
}
}
- /** Whether key will, by default, trigger a click on the focused view.
- * @hide
+ /**
+ * Returns true if the key event should be treated as a confirming action.
+ * @return True for a confirmation key, such as {@link #KEYCODE_DPAD_CENTER},
+ * {@link #KEYCODE_ENTER}, or {@link #KEYCODE_BUTTON_A}.
*/
- public static final boolean isConfirmKey(int keyCode) {
- switch (keyCode) {
+ public final boolean isConfirmKey() {
+ switch (mKeyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_BUTTON_A:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the key event should be treated as a cancelling action.
+ * @return True for a cancellation key, such as {@link #KEYCODE_ESCAPE},
+ * {@link #KEYCODE_BACK}, or {@link #KEYCODE_BUTTON_B}.
+ */
+ public final boolean isCancelKey() {
+ switch (mKeyCode) {
+ case KeyEvent.KEYCODE_BUTTON_B:
+ case KeyEvent.KEYCODE_ESCAPE:
+ case KeyEvent.KEYCODE_BACK:
return true;
default:
return false;
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index a7ee12b..71296fa 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -161,6 +161,7 @@ public class MenuInflater {
} else if (tagName.equals(XML_MENU)) {
// A menu start tag denotes a submenu for an item
SubMenu subMenu = menuState.addSubMenuItem();
+ registerMenu(subMenu, attrs);
// Parse the submenu into returned SubMenu
parseMenu(parser, attrs, subMenu);
@@ -183,9 +184,9 @@ public class MenuInflater {
if (!menuState.hasAddedItem()) {
if (menuState.itemActionProvider != null &&
menuState.itemActionProvider.hasSubMenu()) {
- menuState.addSubMenuItem();
+ registerMenu(menuState.addSubMenuItem(), attrs);
} else {
- menuState.addItem();
+ registerMenu(menuState.addItem(), attrs);
}
}
} else if (tagName.equals(XML_MENU)) {
@@ -200,7 +201,30 @@ public class MenuInflater {
eventType = parser.next();
}
}
-
+
+ /**
+ * The method is a hook for layoutlib to do its magic.
+ * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
+ * appears to do nothing.
+ */
+ private void registerMenu(@SuppressWarnings("unused") MenuItem item,
+ @SuppressWarnings("unused") AttributeSet set) {
+ }
+
+ /**
+ * The method is a hook for layoutlib to do its magic.
+ * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
+ * appears to do nothing.
+ */
+ private void registerMenu(@SuppressWarnings("unused") SubMenu subMenu,
+ @SuppressWarnings("unused") AttributeSet set) {
+ }
+
+ // Needed by layoutlib.
+ /*package*/ Context getContext() {
+ return mContext;
+ }
+
private static class InflatedOnMenuItemClickListener
implements MenuItem.OnMenuItemClickListener {
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
@@ -446,9 +470,11 @@ public class MenuInflater {
}
}
- public void addItem() {
+ public MenuItem addItem() {
itemAdded = true;
- setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
+ MenuItem item = menu.add(groupId, itemId, itemCategoryOrder, itemTitle);
+ setItem(item);
+ return item;
}
public SubMenu addSubMenuItem() {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ddce3ce..6378ffd 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3372,11 +3372,11 @@ public final class MotionEvent extends InputEvent implements Parcelable {
throw new IllegalArgumentException("Axis out of range.");
}
final long bits = mPackedAxisBits;
- final long axisBit = 1L << axis;
+ final long axisBit = 0x8000000000000000L >>> axis;
if ((bits & axisBit) == 0) {
return 0;
}
- final int index = Long.bitCount(bits & (axisBit - 1L));
+ final int index = Long.bitCount(bits & ~(0xFFFFFFFFFFFFFFFFL >>> axis));
return mPackedAxisValues[index];
}
}
@@ -3425,8 +3425,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
throw new IllegalArgumentException("Axis out of range.");
}
final long bits = mPackedAxisBits;
- final long axisBit = 1L << axis;
- final int index = Long.bitCount(bits & (axisBit - 1L));
+ final long axisBit = 0x8000000000000000L >>> axis;
+ final int index = Long.bitCount(bits & ~(0xFFFFFFFFFFFFFFFFL >>> axis));
float[] values = mPackedAxisValues;
if ((bits & axisBit) == 0) {
if (values == null) {
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/View.java b/core/java/android/view/View.java
index bdf4141..eb7f45e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2269,6 +2269,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
static final int PFLAG3_CALLED_SUPER = 0x10;
+ /**
+ * Flag indicating that we're in the process of applying window insets.
+ */
+ static final int PFLAG3_APPLYING_INSETS = 0x40;
+
+ /**
+ * Flag indicating that we're in the process of fitting system windows using the old method.
+ */
+ static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
/* End of masks for mPrivateFlags3 */
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
@@ -3178,6 +3188,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
+ OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
}
ListenerInfo mListenerInfo;
@@ -5903,8 +5915,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getFitsSystemWindows()
* @see #setFitsSystemWindows(boolean)
* @see #setSystemUiVisibility(int)
+ *
+ * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
+ * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
+ * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
+ * to implement handling their own insets.
*/
protected boolean fitSystemWindows(Rect insets) {
+ if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+ // If we're not in the process of dispatching the newer apply insets call,
+ // that means we're not in the compatibility path. Dispatch into the newer
+ // apply insets path and take things from there.
+ try {
+ mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+ } finally {
+ mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ }
+ } else {
+ // We're being called from the newer apply insets path.
+ // Perform the standard fallback behavior.
+ return fitSystemWindowsInt(insets);
+ }
+ }
+
+ private boolean fitSystemWindowsInt(Rect insets) {
if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
@@ -5924,6 +5959,97 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Called when the view should apply {@link WindowInsets} according to its internal policy.
+ *
+ * <p>This method should be overridden by views that wish to apply a policy different from or
+ * in addition to the default behavior. Clients that wish to force a view subtree
+ * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p>
+ *
+ * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
+ * it will be called during dispatch instead of this method. The listener may optionally
+ * call this method from its own implementation if it wishes to apply the view's default
+ * insets policy in addition to its own.</p>
+ *
+ * <p>Implementations of this method should either return the insets parameter unchanged
+ * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed
+ * that this view applied itself. This allows new inset types added in future platform
+ * versions to pass through existing implementations unchanged without being erroneously
+ * consumed.</p>
+ *
+ * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows}
+ * property is set then the view will consume the system window insets and apply them
+ * as padding for the view.</p>
+ *
+ * @param insets Insets to apply
+ * @return The supplied insets with any applied insets consumed
+ */
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
+ // We weren't called from within a direct call to fitSystemWindows,
+ // call into it as a fallback in case we're in a class that overrides it
+ // and has logic to perform.
+ if (fitSystemWindows(insets.getSystemWindowInsets())) {
+ return insets.cloneWithSystemWindowInsetsConsumed();
+ }
+ } else {
+ // We were called from within a direct call to fitSystemWindows.
+ if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+ return insets.cloneWithSystemWindowInsetsConsumed();
+ }
+ }
+ return insets;
+ }
+
+ /**
+ * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
+ * window insets to this view. The listener's
+ * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+ * method will be called instead of the view's
+ * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+ *
+ * @param listener Listener to set
+ *
+ * @see #onApplyWindowInsets(WindowInsets)
+ */
+ public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
+ getListenerInfo().mOnApplyWindowInsetsListener = listener;
+ }
+
+ /**
+ * Request to apply the given window insets to this view or another view in its subtree.
+ *
+ * <p>This method should be called by clients wishing to apply insets corresponding to areas
+ * obscured by window decorations or overlays. This can include the status and navigation bars,
+ * action bars, input methods and more. New inset categories may be added in the future.
+ * The method returns the insets provided minus any that were applied by this view or its
+ * children.</p>
+ *
+ * <p>Clients wishing to provide custom behavior should override the
+ * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a
+ * {@link OnApplyWindowInsetsListener} via the
+ * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener}
+ * method.</p>
+ *
+ * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method.
+ * </p>
+ *
+ * @param insets Insets to apply
+ * @return The provided insets minus the insets that were consumed
+ */
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ try {
+ mPrivateFlags3 |= PFLAG3_APPLYING_INSETS;
+ if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+ return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
+ } else {
+ return onApplyWindowInsets(insets);
+ }
+ } finally {
+ mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS;
+ }
+ }
+
+ /**
* @hide Compute the insets that should be consumed by this view and the ones
* that should propagate to those under it.
*/
@@ -5995,6 +6121,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
+ * @deprecated Use {@link #requestApplyInsets()} for newer platform versions.
*/
public void requestFitSystemWindows() {
if (mParent != null) {
@@ -6003,6 +6130,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed.
+ */
+ public void requestApplyInsets() {
+ requestFitSystemWindows();
+ }
+
+ /**
* For use by PhoneWindow to make its own system window fitting optional.
* @hide
*/
@@ -6543,7 +6677,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_filterTouchesWhenObscured
*/
public void setFilterTouchesWhenObscured(boolean enabled) {
- setFlags(enabled ? 0 : FILTER_TOUCHES_WHEN_OBSCURED,
+ setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0,
FILTER_TOUCHES_WHEN_OBSCURED);
}
@@ -8186,7 +8320,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean result = false;
- if (KeyEvent.isConfirmKey(keyCode)) {
+ if (event.isConfirmKey()) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
@@ -8228,7 +8362,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (KeyEvent.isConfirmKey(keyCode)) {
+ if (event.isConfirmKey()) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
@@ -16499,7 +16633,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
- setMeasuredDimension((int) (value >> 32), (int) value);
+ setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
@@ -16594,6 +16728,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
measuredWidth += optical ? opticalWidth : -opticalWidth;
measuredHeight += optical ? opticalHeight : -opticalHeight;
}
+ setMeasuredDimensionRaw(measuredWidth, measuredHeight);
+ }
+
+ /**
+ * Sets the measured dimension without extra processing for things like optical bounds.
+ * Useful for reapplying consistent values that have already been cooked with adjustments
+ * for optical bounds, etc. such as those from the measurement cache.
+ *
+ * @param measuredWidth The measured width of this view. May be a complex
+ * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
+ * {@link #MEASURED_STATE_TOO_SMALL}.
+ * @param measuredHeight The measured height of this view. May be a complex
+ * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
+ * {@link #MEASURED_STATE_TOO_SMALL}.
+ */
+ private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
@@ -16824,8 +16974,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// If the screen is off assume the animation start time is now instead of
// the next frame we draw. Keeping the START_ON_FIRST_FRAME start time
// would cause the animation to start when the screen turns back on
- if (mAttachInfo != null && !mAttachInfo.mScreenOn &&
- animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
+ if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF
+ && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
}
animation.reset();
@@ -18361,7 +18511,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
static int adjust(int measureSpec, int delta) {
- return makeMeasureSpec(getSize(measureSpec + delta), getMode(measureSpec));
+ final int mode = getMode(measureSpec);
+ if (mode == UNSPECIFIED) {
+ // No need to adjust size for UNSPECIFIED mode.
+ return makeMeasureSpec(0, UNSPECIFIED);
+ }
+ int size = getSize(measureSpec) + delta;
+ if (size < 0) {
+ Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
+ ") spec: " + toString(measureSpec) + " delta: " + delta);
+ size = 0;
+ }
+ return makeMeasureSpec(size, mode);
}
/**
@@ -18641,6 +18802,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public void onViewDetachedFromWindow(View v);
}
+ /**
+ * Listener for applying window insets on a view in a custom way.
+ *
+ * <p>Apps may choose to implement this interface if they want to apply custom policy
+ * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
+ * is set, its
+ * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+ * method will be called instead of the View's own
+ * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener
+ * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply
+ * the View's normal behavior as part of its own.</p>
+ */
+ public interface OnApplyWindowInsetsListener {
+ /**
+ * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set}
+ * on a View, this listener method will be called instead of the view's own
+ * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+ *
+ * @param v The view applying window insets
+ * @param insets The insets to apply
+ * @return The insets supplied, minus any insets that were consumed
+ */
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
+ }
+
private final class UnsetPressedState implements Runnable {
public void run() {
setPressed(false);
@@ -18686,7 +18872,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* A set of information given to a view when it is attached to its parent
* window.
*/
- static class AttachInfo {
+ final static class AttachInfo {
interface Callbacks {
void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always);
@@ -18752,7 +18938,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mHardwareAccelerationRequested;
HardwareRenderer mHardwareRenderer;
- boolean mScreenOn;
+ /**
+ * The state of the display to which the window is attached, as reported
+ * by {@link Display#getState()}. Note that the display state constants
+ * declared by {@link Display} do not exactly line up with the screen state
+ * constants declared by {@link View} (there are more display states than
+ * screen states).
+ */
+ int mDisplayState = Display.STATE_UNKNOWN;
/**
* Scale factor used by the compatibility mode
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index c3f064f..e67659c 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -212,6 +212,14 @@ public class ViewConfiguration {
*/
private static final int OVERFLING_DISTANCE = 6;
+ /**
+ * Configuration values for overriding {@link #hasPermanentMenuKey()} behavior.
+ * These constants must match the definition in res/values/config.xml.
+ */
+ private static final int HAS_PERMANENT_MENU_KEY_AUTODETECT = 0;
+ private static final int HAS_PERMANENT_MENU_KEY_TRUE = 1;
+ private static final int HAS_PERMANENT_MENU_KEY_FALSE = 2;
+
private final int mEdgeSlop;
private final int mFadingEdgeLength;
private final int mMinimumFlingVelocity;
@@ -296,12 +304,31 @@ public class ViewConfiguration {
mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
if (!sHasPermanentMenuKeySet) {
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- try {
- sHasPermanentMenuKey = !wm.hasNavigationBar();
- sHasPermanentMenuKeySet = true;
- } catch (RemoteException ex) {
- sHasPermanentMenuKey = false;
+ final int configVal = res.getInteger(
+ com.android.internal.R.integer.config_overrideHasPermanentMenuKey);
+
+ switch (configVal) {
+ default:
+ case HAS_PERMANENT_MENU_KEY_AUTODETECT: {
+ IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ sHasPermanentMenuKey = !wm.hasNavigationBar();
+ sHasPermanentMenuKeySet = true;
+ } catch (RemoteException ex) {
+ sHasPermanentMenuKey = false;
+ }
+ }
+ break;
+
+ case HAS_PERMANENT_MENU_KEY_TRUE:
+ sHasPermanentMenuKey = true;
+ sHasPermanentMenuKeySet = true;
+ break;
+
+ case HAS_PERMANENT_MENU_KEY_FALSE:
+ sHasPermanentMenuKey = false;
+ sHasPermanentMenuKeySet = true;
+ break;
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9414237..f346ee8 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++) {
@@ -5430,21 +5429,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
-
@Override
- protected boolean fitSystemWindows(Rect insets) {
- boolean done = super.fitSystemWindows(insets);
- if (!done) {
- final int count = mChildrenCount;
- final View[] children = mChildren;
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ insets = super.dispatchApplyWindowInsets(insets);
+ if (insets.hasInsets()) {
+ final int count = getChildCount();
for (int i = 0; i < count; i++) {
- done = children[i].fitSystemWindows(insets);
- if (done) {
+ insets = getChildAt(i).dispatchApplyWindowInsets(insets);
+ if (!insets.hasInsets()) {
break;
}
}
}
- return done;
+ return insets;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3fd2aa9..1cb0473 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -36,6 +36,8 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Bundle;
@@ -134,6 +136,7 @@ public final class ViewRootImpl implements ViewParent,
final Context mContext;
final IWindowSession mWindowSession;
final Display mDisplay;
+ final DisplayManager mDisplayManager;
final String mBasePackageName;
final int[] mTmpLocation = new int[2];
@@ -232,8 +235,6 @@ public final class ViewRootImpl implements ViewParent,
InputStage mFirstInputStage;
InputStage mFirstPostImeInputStage;
- boolean mFlipControllerFallbackKeys;
-
boolean mWindowAttributesChanged = false;
int mWindowAttributesChangesFlag = 0;
@@ -370,11 +371,7 @@ 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();
+ mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
}
@@ -429,6 +426,10 @@ public final class ViewRootImpl implements ViewParent,
synchronized (this) {
if (mView == null) {
mView = view;
+
+ mAttachInfo.mDisplayState = mDisplay.getState();
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
@@ -798,18 +799,43 @@ public final class ViewRootImpl implements ViewParent,
scheduleTraversals();
}
- void handleScreenStateChange(boolean on) {
- if (on != mAttachInfo.mScreenOn) {
- mAttachInfo.mScreenOn = on;
- if (mView != null) {
- mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
- }
- if (on) {
- mFullRedrawNeeded = true;
- scheduleTraversals();
+ private final DisplayListener mDisplayListener = new DisplayListener() {
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (mView != null && mDisplay.getDisplayId() == displayId) {
+ final int oldDisplayState = mAttachInfo.mDisplayState;
+ final int newDisplayState = mDisplay.getState();
+ if (oldDisplayState != newDisplayState) {
+ mAttachInfo.mDisplayState = newDisplayState;
+ if (oldDisplayState != Display.STATE_UNKNOWN) {
+ final int oldScreenState = toViewScreenState(oldDisplayState);
+ final int newScreenState = toViewScreenState(newDisplayState);
+ if (oldScreenState != newScreenState) {
+ mView.dispatchScreenStateChanged(newScreenState);
+ }
+ if (oldDisplayState == Display.STATE_OFF) {
+ // Draw was suppressed so we need to for it to happen here.
+ mFullRedrawNeeded = true;
+ scheduleTraversals();
+ }
+ }
+ }
}
}
- }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ }
+
+ private int toViewScreenState(int displayState) {
+ return displayState == Display.STATE_OFF ?
+ View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
+ }
+ };
@Override
public void requestFitSystemWindows() {
@@ -1125,6 +1151,19 @@ public final class ViewRootImpl implements ViewParent,
return windowSizeMayChange;
}
+ void dispatchApplyInsets(View host) {
+ mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+ boolean isRound = false;
+ if ((mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && mDisplay.getDisplayId() == 0) {
+ // we're fullscreen and not hosted in an ActivityView
+ isRound = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound);
+ }
+ host.dispatchApplyWindowInsets(new WindowInsets(
+ mFitSystemWindowsInsets, isRound));
+ }
+
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
@@ -1216,8 +1255,7 @@ public final class ViewRootImpl implements ViewParent,
}
host.dispatchAttachedToWindow(attachInfo, 0);
attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
- mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
- host.fitSystemWindows(mFitSystemWindowsInsets);
+ dispatchApplyInsets(host);
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
@@ -1342,9 +1380,8 @@ public final class ViewRootImpl implements ViewParent,
if (mFitSystemWindowsRequested) {
mFitSystemWindowsRequested = false;
- mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
mLastOverscanRequested = mAttachInfo.mOverscanRequested;
- host.fitSystemWindows(mFitSystemWindowsInsets);
+ dispatchApplyInsets(host);
if (mLayoutRequested) {
// Short-circuit catching a new layout request here, so
// we don't need to go through two layout passes when things
@@ -1523,8 +1560,7 @@ public final class ViewRootImpl implements ViewParent,
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
mLastOverscanRequested = mAttachInfo.mOverscanRequested;
mFitSystemWindowsRequested = false;
- mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
- host.fitSystemWindows(mFitSystemWindowsInsets);
+ dispatchApplyInsets(host);
}
if (visibleInsetsChanged) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
@@ -2240,7 +2276,7 @@ public final class ViewRootImpl implements ViewParent,
}
private void performDraw() {
- if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
+ if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
}
@@ -2876,6 +2912,8 @@ public final class ViewRootImpl implements ViewParent,
mInputChannel = null;
}
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+
unscheduleTraversals();
}
@@ -2912,11 +2950,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).
*/
@@ -2958,7 +2993,6 @@ public final class ViewRootImpl implements ViewParent,
private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
private final static int MSG_UPDATE_CONFIGURATION = 18;
private final static int MSG_PROCESS_INPUT_EVENTS = 19;
- private final static int MSG_DISPATCH_SCREEN_STATE = 20;
private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
private final static int MSG_INVALIDATE_WORLD = 23;
@@ -3005,8 +3039,6 @@ public final class ViewRootImpl implements ViewParent,
return "MSG_UPDATE_CONFIGURATION";
case MSG_PROCESS_INPUT_EVENTS:
return "MSG_PROCESS_INPUT_EVENTS";
- case MSG_DISPATCH_SCREEN_STATE:
- return "MSG_DISPATCH_SCREEN_STATE";
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
case MSG_DISPATCH_DONE_ANIMATING:
@@ -3222,11 +3254,6 @@ public final class ViewRootImpl implements ViewParent,
}
updateConfiguration(config, false);
} break;
- case MSG_DISPATCH_SCREEN_STATE: {
- if (mView != null) {
- handleScreenStateChange(msg.arg1 == 1);
- }
- } break;
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
setAccessibilityFocus(null, null);
} break;
@@ -3699,7 +3726,8 @@ public final class ViewRootImpl implements ViewParent,
if (result == InputMethodManager.DISPATCH_HANDLED) {
return FINISH_HANDLED;
} else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
- return FINISH_NOT_HANDLED;
+ // The IME could not handle it, so skip along to the next InputStage
+ return FORWARD;
} else {
return DEFER; // callback will be invoked later
}
@@ -3985,7 +4013,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 +4035,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;
}
@@ -4332,6 +4354,7 @@ public final class ViewRootImpl implements ViewParent,
* Creates dpad events from unhandled joystick movements.
*/
final class SyntheticJoystickHandler extends Handler {
+ private final static String TAG = "SyntheticJoystickHandler";
private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
@@ -4364,10 +4387,21 @@ public final class ViewRootImpl implements ViewParent,
}
public void process(MotionEvent event) {
- update(event, true);
+ switch(event.getActionMasked()) {
+ case MotionEvent.ACTION_CANCEL:
+ cancel(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ update(event, true);
+ break;
+ default:
+ Log.w(TAG, "Unexpected action: " + event.getActionMasked());
+ }
}
- public void cancel(MotionEvent event) {
+ private void cancel(MotionEvent event) {
+ removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
+ removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
update(event, false);
}
@@ -4843,63 +4877,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.
@@ -5863,12 +5840,6 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendMessage(msg);
}
- public void dispatchScreenStateChange(boolean on) {
- Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
- msg.arg1 = on ? 1 : 0;
- mHandler.sendMessage(msg);
- }
-
public void dispatchGetNewSurface() {
Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
mHandler.sendMessage(msg);
@@ -6207,14 +6178,6 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void dispatchScreenState(boolean on) {
- final ViewRootImpl viewAncestor = mViewAncestor.get();
- if (viewAncestor != null) {
- viewAncestor.dispatchScreenStateChange(on);
- }
- }
-
- @Override
public void dispatchGetNewSurface() {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
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/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644
index 0000000..2160efe
--- /dev/null
+++ b/core/java/android/view/WindowInsets.java
@@ -0,0 +1,304 @@
+/*
+ * 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.graphics.Rect;
+
+/**
+ * Describes a set of insets for window content.
+ *
+ * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
+ * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
+ * with the adjusted properties.</p>
+ *
+ * @see View.OnApplyWindowInsetsListener
+ * @see View#onApplyWindowInsets(WindowInsets)
+ */
+public class WindowInsets {
+ private Rect mSystemWindowInsets;
+ private Rect mWindowDecorInsets;
+ private Rect mTempRect;
+ private boolean mIsRound;
+
+ private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+
+ /**
+ * Since new insets may be added in the future that existing apps couldn't
+ * know about, this fully empty constant shouldn't be made available to apps
+ * since it would allow them to inadvertently consume unknown insets by returning it.
+ * @hide
+ */
+ public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
+ this(systemWindowInsets, windowDecorInsets, false);
+ }
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets, boolean isRound) {
+ this(systemWindowInsets, EMPTY_RECT, isRound);
+ }
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
+ mSystemWindowInsets = systemWindowInsets;
+ mWindowDecorInsets = windowDecorInsets;
+ mIsRound = isRound;
+ }
+
+ /**
+ * Construct a new WindowInsets, copying all values from a source WindowInsets.
+ *
+ * @param src Source to copy insets from
+ */
+ public WindowInsets(WindowInsets src) {
+ mSystemWindowInsets = src.mSystemWindowInsets;
+ mWindowDecorInsets = src.mWindowDecorInsets;
+ mIsRound = src.mIsRound;
+ }
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets) {
+ this(systemWindowInsets, EMPTY_RECT);
+ }
+
+ /**
+ * Used to provide a safe copy of the system window insets to pass through
+ * to the existing fitSystemWindows method and other similar internals.
+ * @hide
+ */
+ public Rect getSystemWindowInsets() {
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+ mTempRect.set(mSystemWindowInsets);
+ return mTempRect;
+ }
+
+ /**
+ * Returns the left system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The left system window inset
+ */
+ public int getSystemWindowInsetLeft() {
+ return mSystemWindowInsets.left;
+ }
+
+ /**
+ * Returns the top system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The top system window inset
+ */
+ public int getSystemWindowInsetTop() {
+ return mSystemWindowInsets.top;
+ }
+
+ /**
+ * Returns the right system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The right system window inset
+ */
+ public int getSystemWindowInsetRight() {
+ return mSystemWindowInsets.right;
+ }
+
+ /**
+ * Returns the bottom system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The bottom system window inset
+ */
+ public int getSystemWindowInsetBottom() {
+ return mSystemWindowInsets.bottom;
+ }
+
+ /**
+ * Returns the left window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The left window decor inset
+ */
+ public int getWindowDecorInsetLeft() {
+ return mWindowDecorInsets.left;
+ }
+
+ /**
+ * Returns the top window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The top window decor inset
+ */
+ public int getWindowDecorInsetTop() {
+ return mWindowDecorInsets.top;
+ }
+
+ /**
+ * Returns the right window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The right window decor inset
+ */
+ public int getWindowDecorInsetRight() {
+ return mWindowDecorInsets.right;
+ }
+
+ /**
+ * Returns the bottom window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The bottom window decor inset
+ */
+ public int getWindowDecorInsetBottom() {
+ return mWindowDecorInsets.bottom;
+ }
+
+ /**
+ * Returns true if this WindowInsets has nonzero system window insets.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return true if any of the system window inset values are nonzero
+ */
+ public boolean hasSystemWindowInsets() {
+ return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
+ mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
+ }
+
+ /**
+ * Returns true if this WindowInsets has nonzero window decor insets.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return true if any of the window decor inset values are nonzero
+ */
+ public boolean hasWindowDecorInsets() {
+ return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
+ mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
+ }
+
+ /**
+ * Returns true if this WindowInsets has any nonzero insets.
+ *
+ * @return true if any inset values are nonzero
+ */
+ public boolean hasInsets() {
+ return hasSystemWindowInsets() || hasWindowDecorInsets();
+ }
+
+ /**
+ * Returns true if the associated window has a round shape.
+ *
+ * <p>A round window's left, top, right and bottom edges reach all the way to the
+ * associated edges of the window but the corners may not be visible. Views responding
+ * to round insets should take care to not lay out critical elements within the corners
+ * where they may not be accessible.</p>
+ *
+ * @return True if the window is round
+ */
+ public boolean isRound() {
+ return mIsRound;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+ return result;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+ boolean right, boolean bottom) {
+ if (left || top || right || bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+ top ? 0 : mSystemWindowInsets.top,
+ right ? 0 : mSystemWindowInsets.right,
+ bottom ? 0 : mSystemWindowInsets.bottom);
+ return result;
+ }
+ return this;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+ return result;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets.set(0, 0, 0, 0);
+ return result;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+ boolean right, boolean bottom) {
+ if (left || top || right || bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
+ top ? 0 : mWindowDecorInsets.top,
+ right ? 0 : mWindowDecorInsets.right,
+ bottom ? 0 : mWindowDecorInsets.bottom);
+ return result;
+ }
+ return this;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets + " windowDecorInsets=" +
+ mWindowDecorInsets + (isRound() ? "round}" : "}");
+ }
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0ce4da5..d5a7d33 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -610,7 +610,10 @@ public interface WindowManager extends ViewManager {
* screen is pressed, you will receive this first touch event. Usually
* the first touch event is consumed by the system since the user can
* not see what they are pressing on.
+ *
+ * @deprecated This flag has no effect.
*/
+ @Deprecated
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
/** Window flag: as long as this window is visible to the user, keep
@@ -1063,13 +1066,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..893db89 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -86,8 +86,7 @@ public interface WindowManagerPolicy {
public final static int FLAG_FILTERED = 0x04000000;
public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
- public final static int FLAG_WOKE_HERE = 0x10000000;
- public final static int FLAG_BRIGHT_HERE = 0x20000000;
+ public final static int FLAG_INTERACTIVE = 0x20000000;
public final static int FLAG_PASS_TO_USER = 0x40000000;
// Flags used for indicating whether the internal and/or external input devices
@@ -115,20 +114,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().
@@ -749,12 +734,10 @@ public interface WindowManagerPolicy {
* because it's the most fragile.
* @param event The key event.
* @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);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
/**
* Called from the input reader thread before a motion is enqueued when the screen is off.
@@ -765,10 +748,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 interceptWakeMotionBeforeQueueing(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..bbaa33d 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);
@@ -2076,22 +2076,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mInLayout = true;
+ final int childCount = getChildCount();
if (changed) {
- int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
getChildAt(i).forceLayout();
}
mRecycler.markChildrenDirty();
}
- if (mFastScroller != null && (mItemCount != mOldItemCount || mDataChanged)) {
- mFastScroller.onItemCountChanged(mItemCount);
- }
-
layoutChildren();
mInLayout = false;
mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;
+
+ // TODO: Move somewhere sane. This doesn't belong in onLayout().
+ if (mFastScroller != null) {
+ mFastScroller.onItemCountChanged(getChildCount(), mItemCount);
+ }
}
/**
@@ -2228,26 +2229,34 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView");
isScrap[0] = false;
- View scrapView;
- scrapView = mRecycler.getTransientStateView(position);
- if (scrapView == null) {
- scrapView = mRecycler.getScrapView(position);
- }
+ // Check whether we have a transient state view. Attempt to re-bind the
+ // data and discard the view if we fail.
+ final View transientView = mRecycler.getTransientStateView(position);
+ if (transientView != null) {
+ final LayoutParams params = (LayoutParams) transientView.getLayoutParams();
- View child;
- if (scrapView != null) {
- child = mAdapter.getView(position, scrapView, this);
+ // If the view type hasn't changed, attempt to re-bind the data.
+ if (params.viewType == mAdapter.getItemViewType(position)) {
+ final View updatedView = mAdapter.getView(position, transientView, this);
- if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
- child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ // If we failed to re-bind the data, scrap the obtained view.
+ if (updatedView != transientView) {
+ mRecycler.addScrapView(updatedView, position);
+ }
}
+ // Scrap view implies temporary detachment.
+ isScrap[0] = true;
+ return transientView;
+ }
+
+ final View scrapView = mRecycler.getScrapView(position);
+ final View child = mAdapter.getView(position, scrapView, this);
+ if (scrapView != null) {
if (child != scrapView) {
+ // Failed to re-bind the data, return scrap to the heap.
mRecycler.addScrapView(scrapView, position);
- if (mCacheColorHint != 0) {
- child.setDrawingCacheBackgroundColor(mCacheColorHint);
- }
} else {
isScrap[0] = true;
@@ -2259,16 +2268,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
child.dispatchFinishTemporaryDetach();
}
- } else {
- child = mAdapter.getView(position, null, this);
+ }
- if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
- child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
+ if (mCacheColorHint != 0) {
+ child.setDrawingCacheBackgroundColor(mCacheColorHint);
+ }
- if (mCacheColorHint != 0) {
- child.setDrawingCacheBackgroundColor(mCacheColorHint);
- }
+ if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+ child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
if (mAdapterHasStableIds) {
@@ -3032,7 +3039,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (KeyEvent.isConfirmKey(keyCode)) {
+ if (event.isConfirmKey()) {
if (!isEnabled()) {
return true;
}
@@ -6562,12 +6569,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
}
- if (mTransientStateViews != null) {
- mTransientStateViews.clear();
- }
- if (mTransientStateViewsById != null) {
- mTransientStateViewsById.clear();
- }
+
+ clearTransientStateViews();
}
/**
@@ -6634,14 +6637,26 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
- * Dump any currently saved views with transient state.
+ * Dumps and fully detaches any currently saved views with transient
+ * state.
*/
void clearTransientStateViews() {
- if (mTransientStateViews != null) {
- mTransientStateViews.clear();
+ final SparseArray<View> viewsByPos = mTransientStateViews;
+ if (viewsByPos != null) {
+ final int N = viewsByPos.size();
+ for (int i = 0; i < N; i++) {
+ removeDetachedView(viewsByPos.valueAt(i), false);
+ }
+ viewsByPos.clear();
}
- if (mTransientStateViewsById != null) {
- mTransientStateViewsById.clear();
+
+ final LongSparseArray<View> viewsById = mTransientStateViewsById;
+ if (viewsById != null) {
+ final int N = viewsById.size();
+ for (int i = 0; i < N; i++) {
+ removeDetachedView(viewsById.valueAt(i), false);
+ }
+ viewsById.clear();
}
}
@@ -6766,44 +6781,48 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (victim != null) {
final AbsListView.LayoutParams lp
= (AbsListView.LayoutParams) victim.getLayoutParams();
- int whichScrap = lp.viewType;
+ final int whichScrap = lp.viewType;
activeViews[i] = null;
- final boolean scrapHasTransientState = victim.hasTransientState();
- if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) {
- // Do not move views that should be ignored
- if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER &&
- scrapHasTransientState) {
+ if (victim.hasTransientState()) {
+ // Store views with transient state for later use.
+ victim.dispatchStartTemporaryDetach();
+
+ if (mAdapter != null && mAdapterHasStableIds) {
+ if (mTransientStateViewsById == null) {
+ mTransientStateViewsById = new LongSparseArray<View>();
+ }
+ long id = mAdapter.getItemId(mFirstActivePosition + i);
+ mTransientStateViewsById.put(id, victim);
+ } else if (!mDataChanged) {
+ if (mTransientStateViews == null) {
+ mTransientStateViews = new SparseArray<View>();
+ }
+ mTransientStateViews.put(mFirstActivePosition + i, victim);
+ } else if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
+ // The data has changed, we can't keep this view.
removeDetachedView(victim, false);
}
- if (scrapHasTransientState) {
- if (mAdapter != null && mAdapterHasStableIds) {
- if (mTransientStateViewsById == null) {
- mTransientStateViewsById = new LongSparseArray<View>();
- }
- long id = mAdapter.getItemId(mFirstActivePosition + i);
- mTransientStateViewsById.put(id, victim);
- } else {
- if (mTransientStateViews == null) {
- mTransientStateViews = new SparseArray<View>();
- }
- mTransientStateViews.put(mFirstActivePosition + i, victim);
- }
+ } else if (!shouldRecycleViewType(whichScrap)) {
+ // Discard non-recyclable views except headers/footers.
+ if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
+ removeDetachedView(victim, false);
+ }
+ } else {
+ // Store everything else on the appropriate scrap heap.
+ if (multipleScraps) {
+ scrapViews = mScrapViews[whichScrap];
}
- continue;
- }
- if (multipleScraps) {
- scrapViews = mScrapViews[whichScrap];
- }
- victim.dispatchStartTemporaryDetach();
- lp.scrappedFromPosition = mFirstActivePosition + i;
- scrapViews.add(victim);
+ victim.dispatchStartTemporaryDetach();
+ lp.scrappedFromPosition = mFirstActivePosition + i;
+ scrapViews.add(victim);
- victim.setAccessibilityDelegate(null);
- if (hasListener) {
- mRecyclerListener.onMovedToScrapHeap(victim);
+ victim.setAccessibilityDelegate(null);
+ if (hasListener) {
+ mRecyclerListener.onMovedToScrapHeap(victim);
+ }
}
}
}
@@ -6812,8 +6831,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
- * Makes sure that the size of mScrapViews does not exceed the size of mActiveViews.
- * (This can happen if an adapter does not recycle its views).
+ * Makes sure that the size of mScrapViews does not exceed the size of
+ * mActiveViews, which can happen if an adapter does not recycle its
+ * views. Removes cached transient state views that no longer have
+ * transient state.
*/
private void pruneScrapViews() {
final int maxViews = mActiveViews.length;
@@ -6829,20 +6850,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
- if (mTransientStateViews != null) {
- for (int i = 0; i < mTransientStateViews.size(); i++) {
- final View v = mTransientStateViews.valueAt(i);
+ final SparseArray<View> transViewsByPos = mTransientStateViews;
+ if (transViewsByPos != null) {
+ for (int i = 0; i < transViewsByPos.size(); i++) {
+ final View v = transViewsByPos.valueAt(i);
if (!v.hasTransientState()) {
- mTransientStateViews.removeAt(i);
+ removeDetachedView(v, false);
+ transViewsByPos.removeAt(i);
i--;
}
}
}
- if (mTransientStateViewsById != null) {
- for (int i = 0; i < mTransientStateViewsById.size(); i++) {
- final View v = mTransientStateViewsById.valueAt(i);
+
+ final LongSparseArray<View> transViewsById = mTransientStateViewsById;
+ if (transViewsById != null) {
+ for (int i = 0; i < transViewsById.size(); i++) {
+ final View v = transViewsById.valueAt(i);
if (!v.hasTransientState()) {
- mTransientStateViewsById.removeAt(i);
+ removeDetachedView(v, false);
+ transViewsById.removeAt(i);
i--;
}
}
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/FastScroller.java b/core/java/android/widget/FastScroller.java
index 01ac8fd..4379bf6 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -224,6 +224,8 @@ class FastScroller {
mHasPendingDrag = false;
}
};
+ private int mOldItemCount;
+ private int mOldChildCount;
/**
* Used to delay hiding fast scroll decorations.
@@ -248,6 +250,8 @@ class FastScroller {
public FastScroller(AbsListView listView) {
mList = listView;
mOverlay = listView.getOverlay();
+ mOldItemCount = listView.getCount();
+ mOldChildCount = listView.getChildCount();
final Context context = listView.getContext();
mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -258,6 +262,7 @@ class FastScroller {
final ImageView trackImage = new ImageView(context);
mTrackImage = trackImage;
+ updateLongList(mOldChildCount, mOldItemCount);
int width = 0;
// Add track to overlay if it has an image.
@@ -445,20 +450,23 @@ class FastScroller {
updateLayout();
}
- public void onItemCountChanged(int totalItemCount) {
- final int visibleItemCount = mList.getChildCount();
- final boolean hasMoreItems = totalItemCount - visibleItemCount > 0;
- if (hasMoreItems && mState != STATE_DRAGGING) {
- final int firstVisibleItem = mList.getFirstVisiblePosition();
- setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount));
- }
+ public void onItemCountChanged(int childCount, int itemCount) {
+ if (mOldItemCount != itemCount || mOldChildCount != childCount) {
+ mOldItemCount = itemCount;
+ mOldChildCount = childCount;
- updateLongList(visibleItemCount, totalItemCount);
+ final boolean hasMoreItems = itemCount - childCount > 0;
+ if (hasMoreItems && mState != STATE_DRAGGING) {
+ final int firstVisibleItem = mList.getFirstVisiblePosition();
+ setThumbPos(getPosFromItemCount(firstVisibleItem, childCount, itemCount));
+ }
+
+ updateLongList(childCount, itemCount);
+ }
}
- private void updateLongList(int visibleItemCount, int totalItemCount) {
- final boolean longList = visibleItemCount > 0
- && totalItemCount / visibleItemCount >= MIN_PAGES;
+ private void updateLongList(int childCount, int itemCount) {
+ final boolean longList = childCount > 0 && itemCount / childCount >= MIN_PAGES;
if (mLongList != longList) {
mLongList = longList;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 78ba6e0..6dd93a7 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1228,7 +1228,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (KeyEvent.isConfirmKey(keyCode)) {
+ if (event.isConfirmKey()) {
if (mReceivedInvokeKeyDown) {
if (mItemCount > 0) {
dispatchPress(mSelectedChild);
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/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 66fe46f..13f3eb6 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -843,7 +843,7 @@ public class ListPopupWindow {
// to select one of its items
if (keyCode != KeyEvent.KEYCODE_SPACE
&& (mDropDownList.getSelectedItemPosition() >= 0
- || !KeyEvent.isConfirmKey(keyCode))) {
+ || !event.isConfirmKey())) {
int curIndex = mDropDownList.getSelectedItemPosition();
boolean consumed;
@@ -931,7 +931,7 @@ public class ListPopupWindow {
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
boolean consumed = mDropDownList.onKeyUp(keyCode, event);
- if (consumed && KeyEvent.isConfirmKey(keyCode)) {
+ if (consumed && event.isConfirmKey()) {
// if the list accepts the key events and the key event was a click, the text view
// gets the selected item from the drop down as its content
dismiss();
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 26c5732..2c44703 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.
*/
@@ -2175,8 +2196,7 @@ public class NumberPicker extends LinearLayout {
@Override
public void run() {
- showSoftInput();
- mIngonreMoveEvents = true;
+ performLongClick();
}
}
@@ -2304,7 +2324,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..fd6ca4c 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -161,9 +161,11 @@ public class ShareActionProvider extends ActionProvider {
@Override
public View onCreateActionView() {
// Create the view and set its data model.
- ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
- activityChooserView.setActivityChooserModel(dataModel);
+ if (!activityChooserView.isInEditMode()) {
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+ activityChooserView.setActivityChooserModel(dataModel);
+ }
// Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();
@@ -266,7 +268,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 3f35875..8460375 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -710,19 +710,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextAppearance_shadowColor:
- shadowcolor = a.getInt(attr, 0);
+ shadowcolor = appearance.getInt(attr, 0);
break;
case com.android.internal.R.styleable.TextAppearance_shadowDx:
- dx = a.getFloat(attr, 0);
+ dx = appearance.getFloat(attr, 0);
break;
case com.android.internal.R.styleable.TextAppearance_shadowDy:
- dy = a.getFloat(attr, 0);
+ dy = appearance.getFloat(attr, 0);
break;
case com.android.internal.R.styleable.TextAppearance_shadowRadius:
- r = a.getFloat(attr, 0);
+ r = appearance.getFloat(attr, 0);
break;
}
}
@@ -8667,6 +8667,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
super.onRtlPropertiesChanged(layoutDirection);
mTextDir = getTextDirectionHeuristic();
+
+ if (mLayout != null) {
+ checkForRelayout();
+ }
}
TextDirectionHeuristic getTextDirectionHeuristic() {
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 066d6c3..ad45894 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -174,6 +174,15 @@ public class ActionBarImpl extends ActionBar {
init(dialog.getWindow().getDecorView());
}
+ /**
+ * Only for edit mode.
+ * @hide
+ */
+ public ActionBarImpl(View layout) {
+ assert layout.isInEditMode();
+ init(layout);
+ }
+
private void init(View decor) {
mContext = decor.getContext();
mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
@@ -559,8 +568,8 @@ public class ActionBarImpl extends ActionBar {
return;
}
- final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
- .disallowAddToBackStack();
+ final FragmentTransaction trans = mActionView.isInEditMode() ? null :
+ mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
if (mSelectedTab == tab) {
if (mSelectedTab != null) {
@@ -578,7 +587,7 @@ public class ActionBarImpl extends ActionBar {
}
}
- if (!trans.isEmpty()) {
+ if (trans != null && !trans.isEmpty()) {
trans.commit();
}
}
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index ab871fb..942995b 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -372,23 +372,25 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
mAppearingPackages = pkgList;
- mChangeType = PACKAGE_TEMPORARY_CHANGE;
+ mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
+ ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE;
mSomePackagesChanged = true;
if (pkgList != null) {
onPackagesAvailable(pkgList);
for (int i=0; i<pkgList.length; i++) {
- onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
+ onPackageAppeared(pkgList[i], mChangeType);
}
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
mDisappearingPackages = pkgList;
- mChangeType = PACKAGE_TEMPORARY_CHANGE;
+ mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
+ ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE;
mSomePackagesChanged = true;
if (pkgList != null) {
onPackagesUnavailable(pkgList);
for (int i=0; i<pkgList.length; i++) {
- onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
+ onPackageDisappeared(pkgList[i], mChangeType);
}
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 2e5fcec..8728610 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -26,6 +26,7 @@ import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFormatException;
@@ -113,6 +114,10 @@ public final class BatteryStatsImpl extends BatteryStats {
}
final class MyHandler extends Handler {
+ public MyHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
@Override
public void handleMessage(Message msg) {
BatteryCallback cb = mCallback;
@@ -4487,9 +4492,9 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public BatteryStatsImpl(String filename) {
+ public BatteryStatsImpl(String filename, Handler handler) {
mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
- mHandler = new MyHandler();
+ mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index f54a3e9..3b0f0f4 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -16,18 +16,11 @@
package com.android.internal.os;
-import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.EventLog;
-import android.util.Log;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
import java.lang.ref.WeakReference;
-import java.lang.reflect.Modifier;
/**
* Private and debugging Binder APIs.
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 3f5ad86..3785b74 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -192,10 +192,16 @@ public class ZygoteInit {
static void closeServerSocket() {
try {
if (sServerSocket != null) {
+ FileDescriptor fd = sServerSocket.getFileDescriptor();
sServerSocket.close();
+ if (fd != null) {
+ Libcore.os.close(fd);
+ }
}
} catch (IOException ex) {
Log.e(TAG, "Zygote: error closing sockets", ex);
+ } catch (libcore.io.ErrnoException ex) {
+ Log.e(TAG, "Zygote: error closing descriptor", ex);
}
sServerSocket = null;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 02bd4ac..86c9fe3 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -57,10 +57,6 @@ public class BaseIWindow extends IWindow.Stub {
}
@Override
- public void dispatchScreenState(boolean on) {
- }
-
- @Override
public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 12ced68..3724a08 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -73,5 +73,5 @@ interface IInputMethodManager {
boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
boolean shouldOfferSwitchingToNextInputMethod(in IBinder token);
boolean setInputMethodEnabled(String id, boolean enabled);
- oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
+ void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 70e2bfc..6295314 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -21,7 +21,6 @@ import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -52,7 +51,9 @@ public final class RotationPolicy {
PackageManager pm = context.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)
&& pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT)
- && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE);
+ && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+ && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_supportAutoRotation);
}
/**
@@ -176,6 +177,7 @@ public final class RotationPolicy {
*/
public static abstract class RotationPolicyListener {
final ContentObserver mObserver = new ContentObserver(new Handler()) {
+ @Override
public void onChange(boolean selfChange, Uri uri) {
RotationPolicyListener.this.onChange();
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 4654178..fe1cf72 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -164,8 +164,24 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
+ final ActionMenuView menuParent = (ActionMenuView) parent;
+ final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
+ if (!menuParent.checkLayoutParams(lp)) {
+ actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
+ }
+ return actionView;
+ }
+
+ @Override
+ public void bindItemView(final MenuItemImpl item, MenuView.ItemView itemView) {
+ itemView.initialize(item, 0);
+
+ final ActionMenuView menuView = (ActionMenuView) mMenuView;
+ final ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
+ actionItemView.setItemInvoker(menuView);
+
if (item.hasSubMenu()) {
- actionView.setOnTouchListener(new ForwardingListener(actionView) {
+ actionItemView.setOnTouchListener(new ForwardingListener(actionItemView) {
@Override
public ListPopupWindow getPopup() {
return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
@@ -182,24 +198,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
});
} else {
- actionView.setOnTouchListener(null);
+ actionItemView.setOnTouchListener(null);
}
-
- final ActionMenuView menuParent = (ActionMenuView) parent;
- final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
- if (!menuParent.checkLayoutParams(lp)) {
- actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
- }
- return actionView;
- }
-
- @Override
- public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
- itemView.initialize(item, 0);
-
- final ActionMenuView menuView = (ActionMenuView) mMenuView;
- ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
- actionItemView.setItemInvoker(menuView);
}
@Override
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index 4882adc..e1bb3621 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -163,7 +163,7 @@ public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClick
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mMenu.performItemAction(mAdapter.getItem(position), 0);
+ mMenu.performItemAction(mAdapter.getItem(position), this, 0);
}
@Override
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index aff697a..5464284 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -247,11 +247,17 @@ public class MenuBuilder implements Menu {
startDispatchingItemsChanged();
}
- private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {
+ private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu,
+ MenuPresenter preferredPresenter) {
if (mPresenters.isEmpty()) return false;
boolean result = false;
+ // Try the preferred presenter first.
+ if (preferredPresenter != null) {
+ result = preferredPresenter.onSubMenuSelected(subMenu);
+ }
+
for (WeakReference<MenuPresenter> ref : mPresenters) {
final MenuPresenter presenter = ref.get();
if (presenter == null) {
@@ -386,8 +392,8 @@ public class MenuBuilder implements Menu {
private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
final int ordering = getOrdering(categoryOrder);
- final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder,
- ordering, title, mDefaultShowAsAction);
+ final MenuItemImpl item = createNewMenuItem(group, id, categoryOrder, ordering, title,
+ mDefaultShowAsAction);
if (mCurrentMenuInfo != null) {
// Pass along the current menu info
@@ -399,7 +405,14 @@ public class MenuBuilder implements Menu {
return item;
}
-
+
+ // Layoutlib overrides this method to return its custom implementation of MenuItemImpl
+ private MenuItemImpl createNewMenuItem(int group, int id, int categoryOrder, int ordering,
+ CharSequence title, int defaultShowAsAction) {
+ return new MenuItemImpl(this, group, id, categoryOrder, ordering, title,
+ defaultShowAsAction);
+ }
+
public MenuItem add(CharSequence title) {
return addInternal(0, 0, 0, title);
}
@@ -865,6 +878,10 @@ public class MenuBuilder implements Menu {
}
public boolean performItemAction(MenuItem item, int flags) {
+ return performItemAction(item, null, flags);
+ }
+
+ public boolean performItemAction(MenuItem item, MenuPresenter preferredPresenter, int flags) {
MenuItemImpl itemImpl = (MenuItemImpl) item;
if (itemImpl == null || !itemImpl.isEnabled()) {
@@ -889,7 +906,7 @@ public class MenuBuilder implements Menu {
if (providerHasSubMenu) {
provider.onPrepareSubMenu(subMenu);
}
- invoked |= dispatchSubMenuSelected(subMenu);
+ invoked |= dispatchSubMenuSelected(subMenu, preferredPresenter);
if (!invoked) close(true);
} else {
if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) {
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 5469b63..c957b67 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@ import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import com.android.internal.app.ActionBarImpl;
import android.content.Context;
@@ -96,7 +97,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
if (mLastSystemUiVisibility != 0) {
int newVis = mLastSystemUiVisibility;
onWindowSystemUiVisibilityChanged(newVis);
- requestFitSystemWindows();
+ requestApplyInsets();
}
}
}
@@ -152,7 +153,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
}
if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
if (mActionBar != null) {
- requestFitSystemWindows();
+ requestApplyInsets();
}
}
}
@@ -190,19 +191,20 @@ public class ActionBarOverlayLayout extends ViewGroup {
}
@Override
- protected boolean fitSystemWindows(Rect insets) {
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
pullChildren();
final int vis = getWindowSystemUiVisibility();
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+ final Rect systemInsets = insets.getSystemWindowInsets();
// The top and bottom action bars are always within the content area.
- boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+ boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
if (mActionBarBottom != null) {
- changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+ changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
}
- mBaseInnerInsets.set(insets);
+ mBaseInnerInsets.set(systemInsets);
computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
changed = true;
@@ -215,9 +217,9 @@ public class ActionBarOverlayLayout extends ViewGroup {
// We don't do any more at this point. To correctly compute the content/inner
// insets in all cases, we need to know the measured size of the various action
- // bar elements. fitSystemWindows() happens before the measure pass, so we can't
+ // bar elements. onApplyWindowInsets() happens before the measure pass, so we can't
// do that here. Instead we will take this up in onMeasure().
- return true;
+ return WindowInsets.EMPTY;
}
@Override
@@ -321,7 +323,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
// the app's fitSystemWindows(). We do this before measuring the content
// view to keep the same semantics as the normal fitSystemWindows() call.
mLastInnerInsets.set(mInnerInsets);
- super.fitSystemWindows(mInnerInsets);
+ mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
}
measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
new file mode 100644
index 0000000..467d42e
--- /dev/null
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -0,0 +1,308 @@
+/*
+ * 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 com.android.internal.widget;
+
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+
+/**
+ * Special layout that finishes its activity when swiped away.
+ */
+public class SwipeDismissLayout extends FrameLayout {
+ private static final String TAG = "SwipeDismissLayout";
+
+ private static final float TRANSLATION_MIN_ALPHA = 0.5f;
+
+ public interface OnDismissedListener {
+ void onDismissed(SwipeDismissLayout layout);
+ }
+
+ public interface OnSwipeProgressChangedListener {
+ /**
+ * Called when the layout has been swiped and the position of the window should change.
+ *
+ * @param progress A number in [-1, 1] representing how far to the left
+ * or right the window has been swiped. Negative values are swipes
+ * left, and positives are right.
+ * @param translate A number in [-w, w], where w is the width of the
+ * layout. This is equivalent to progress * layout.getWidth().
+ */
+ void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate);
+
+ void onSwipeCancelled(SwipeDismissLayout layout);
+ }
+
+ // Cached ViewConfiguration and system-wide constant values
+ private int mSlop;
+ private int mMinFlingVelocity;
+ private int mMaxFlingVelocity;
+ private long mAnimationTime;
+ private TimeInterpolator mCancelInterpolator;
+ private TimeInterpolator mDismissInterpolator;
+
+ // Transient properties
+ private int mActiveTouchId;
+ private float mDownX;
+ private float mDownY;
+ private boolean mSwiping;
+ private boolean mDismissed;
+ private boolean mDiscardIntercept;
+ private VelocityTracker mVelocityTracker;
+ private float mTranslationX;
+
+ private OnDismissedListener mDismissedListener;
+ private OnSwipeProgressChangedListener mProgressListener;
+
+ public SwipeDismissLayout(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public SwipeDismissLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ private void init(Context context) {
+ ViewConfiguration vc = ViewConfiguration.get(getContext());
+ mSlop = vc.getScaledTouchSlop();
+ mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
+ mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+ mAnimationTime = getContext().getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+ mCancelInterpolator = new DecelerateInterpolator(1.5f);
+ mDismissInterpolator = new AccelerateInterpolator(1.5f);
+ }
+
+ public void setOnDismissedListener(OnDismissedListener listener) {
+ mDismissedListener = listener;
+ }
+
+ public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) {
+ mProgressListener = listener;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ // offset because the view is translated during swipe
+ ev.offsetLocation(mTranslationX, 0);
+
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ resetMembers();
+ mDownX = ev.getRawX();
+ mDownY = ev.getRawY();
+ mActiveTouchId = ev.getPointerId(0);
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(ev);
+ break;
+
+ case MotionEvent.ACTION_POINTER_DOWN:
+ int actionIndex = ev.getActionIndex();
+ mActiveTouchId = ev.getPointerId(actionIndex);
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ actionIndex = ev.getActionIndex();
+ int pointerId = ev.getPointerId(actionIndex);
+ if (pointerId == mActiveTouchId) {
+ // This was our active pointer going up. Choose a new active pointer.
+ int newActionIndex = actionIndex == 0 ? 1 : 0;
+ mActiveTouchId = ev.getPointerId(newActionIndex);
+ }
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ resetMembers();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mVelocityTracker == null || mDiscardIntercept) {
+ break;
+ }
+
+ int pointerIndex = ev.findPointerIndex(mActiveTouchId);
+ if (pointerIndex == -1) {
+ Log.e(TAG, "Invalid pointer index: ignoring.");
+ mDiscardIntercept = true;
+ break;
+ }
+ float dx = ev.getRawX() - mDownX;
+ float x = ev.getX(pointerIndex);
+ float y = ev.getY(pointerIndex);
+ if (dx != 0 && canScroll(this, false, dx, x, y)) {
+ mDiscardIntercept = true;
+ break;
+ }
+ updateSwiping(ev);
+ break;
+ }
+
+ return !mDiscardIntercept && mSwiping;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ return super.onTouchEvent(ev);
+ }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_UP:
+ updateDismiss(ev);
+ if (mDismissed) {
+ dismiss();
+ } else if (mSwiping) {
+ cancel();
+ }
+ resetMembers();
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ cancel();
+ resetMembers();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ mVelocityTracker.addMovement(ev);
+ updateSwiping(ev);
+ updateDismiss(ev);
+ if (mSwiping) {
+ setProgress(ev.getRawX() - mDownX);
+ break;
+ }
+ }
+ return true;
+ }
+
+ private void setProgress(float deltaX) {
+ mTranslationX = deltaX;
+ if (mProgressListener != null) {
+ mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX);
+ }
+ }
+
+ private void dismiss() {
+ if (mDismissedListener != null) {
+ mDismissedListener.onDismissed(this);
+ }
+ }
+
+ protected void cancel() {
+ if (mProgressListener != null) {
+ mProgressListener.onSwipeCancelled(this);
+ }
+ }
+
+ /**
+ * Resets internal members when canceling.
+ */
+ private void resetMembers() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = null;
+ mTranslationX = 0;
+ mDownX = 0;
+ mDownY = 0;
+ mSwiping = false;
+ mDismissed = false;
+ mDiscardIntercept = false;
+ }
+
+ private void updateSwiping(MotionEvent ev) {
+ if (!mSwiping) {
+ float deltaX = ev.getRawX() - mDownX;
+ float deltaY = ev.getRawY() - mDownY;
+ mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+ }
+ }
+
+ private void updateDismiss(MotionEvent ev) {
+ float deltaX = ev.getRawX() - mDownX;
+ if (!mDismissed) {
+ mVelocityTracker.addMovement(ev);
+ mVelocityTracker.computeCurrentVelocity(1000);
+
+ float velocityX = mVelocityTracker.getXVelocity();
+ float absVelocityX = Math.abs(velocityX);
+ float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
+
+ if (deltaX > getWidth() / 2) {
+ mDismissed = true;
+ } else if (absVelocityX >= mMinFlingVelocity
+ && absVelocityX <= mMaxFlingVelocity
+ && absVelocityY < absVelocityX / 2
+ && velocityX > 0
+ && deltaX > 0) {
+ mDismissed = true;
+ }
+ }
+ // Check if the user tried to undo this.
+ if (mDismissed && mSwiping) {
+ // Check if the user's finger is actually back
+ if (deltaX < getWidth() / 2) {
+ mDismissed = false;
+ }
+ }
+ }
+
+ /**
+ * Tests scrollability within child views of v in the direction of dx.
+ *
+ * @param v View to test for horizontal scrollability
+ * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+ * or just its children (false).
+ * @param dx Delta scrolled in pixels. Only the sign of this is used.
+ * @param x X coordinate of the active touch point
+ * @param y Y coordinate of the active touch point
+ * @return true if child views of v can be scrolled by delta of dx.
+ */
+ protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) {
+ if (v instanceof ViewGroup) {
+ final ViewGroup group = (ViewGroup) v;
+ final int scrollX = v.getScrollX();
+ final int scrollY = v.getScrollY();
+ final int count = group.getChildCount();
+ for (int i = count - 1; i >= 0; i--) {
+ final View child = group.getChildAt(i);
+ if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
+ y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
+ canScroll(child, true, dx, x + scrollX - child.getLeft(),
+ y + scrollY - child.getTop())) {
+ return true;
+ }
+ }
+ }
+
+ return checkV && v.canScrollHorizontally((int) -dx);
+ }
+}
diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java
new file mode 100644
index 0000000..25dcb30
--- /dev/null
+++ b/core/java/com/android/server/LocalServices.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.android.server;
+
+import android.util.ArrayMap;
+
+/**
+ * This class is used in a similar way as ServiceManager, except the services registered here
+ * are not Binder objects and are only available in the same process.
+ *
+ * Once all services are converted to the SystemService interface, this class can be absorbed
+ * into SystemServiceManager.
+ *
+ * {@hide}
+ */
+public final class LocalServices {
+ private LocalServices() {}
+
+ private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
+ new ArrayMap<Class<?>, Object>();
+
+ /**
+ * Returns a local service instance that implements the specified interface.
+ *
+ * @param type The type of service.
+ * @return The service object.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getService(Class<T> type) {
+ synchronized (sLocalServiceObjects) {
+ return (T) sLocalServiceObjects.get(type);
+ }
+ }
+
+ /**
+ * Adds a service instance of the specified interface to the global registry of local services.
+ */
+ public static <T> void addService(Class<T> type, T service) {
+ synchronized (sLocalServiceObjects) {
+ if (sLocalServiceObjects.containsKey(type)) {
+ throw new IllegalStateException("Overriding service registration");
+ }
+ sLocalServiceObjects.put(type, service);
+ }
+ }
+}
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
new file mode 100644
index 0000000..e374563
--- /dev/null
+++ b/core/java/com/android/server/SystemService.java
@@ -0,0 +1,218 @@
+/*
+ * 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 com.android.server;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * The base class for services running in the system process. Override and implement
+ * the lifecycle event callback methods as needed.
+ * <p>
+ * The lifecycle of a SystemService:
+ * </p><ul>
+ * <li>The constructor is called and provided with the system {@link Context}
+ * to initialize the system service.
+ * <li>{@link #onStart()} is called to get the service running. The service should
+ * publish its binder interface at this point using
+ * {@link #publishBinderService(String, IBinder)}. It may also publish additional
+ * local interfaces that other services within the system server may use to access
+ * privileged internal functions.
+ * <li>Then {@link #onBootPhase(int)} is called as many times as there are boot phases
+ * until {@link #PHASE_BOOT_COMPLETE} is sent, which is the last boot phase. Each phase
+ * is an opportunity to do special work, like acquiring optional service dependencies,
+ * waiting to see if SafeMode is enabled, or registering with a service that gets
+ * started after this one.
+ * </ul><p>
+ * NOTE: All lifecycle methods are called from the system server's main looper thread.
+ * </p>
+ *
+ * {@hide}
+ */
+public abstract class SystemService {
+ /*
+ * Boot Phases
+ */
+ public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?
+
+ /**
+ * After receiving this boot phase, services can obtain lock settings data.
+ */
+ public static final int PHASE_LOCK_SETTINGS_READY = 480;
+
+ /**
+ * After receiving this boot phase, services can safely call into core system services
+ * such as the PowerManager or PackageManager.
+ */
+ public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+
+ /**
+ * After receiving this boot phase, services can broadcast Intents.
+ */
+ public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
+
+ /**
+ * After receiving this boot phase, services can start/bind to third party apps.
+ * Apps will be able to make Binder calls into services at this point.
+ */
+ public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+
+ /**
+ * After receiving this boot phase, services must have finished all boot-related work.
+ */
+ public static final int PHASE_BOOT_COMPLETE = 1000;
+
+ private final Context mContext;
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public SystemService(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Gets the system context.
+ */
+ public final Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns true if the system is running in safe mode.
+ * TODO: we should define in which phase this becomes valid
+ */
+ public final boolean isSafeMode() {
+ return getManager().isSafeMode();
+ }
+
+ /**
+ * Called when the dependencies listed in the @Service class-annotation are available
+ * and after the chosen start phase.
+ * When this method returns, the service should be published.
+ */
+ public abstract void onStart();
+
+ /**
+ * Called on each phase of the boot process. Phases before the service's start phase
+ * (as defined in the @Service annotation) are never received.
+ *
+ * @param phase The current boot phase.
+ */
+ public void onBootPhase(int phase) {}
+
+ /**
+ * Publish the service so it is accessible to other services and apps.
+ */
+ protected final void publishBinderService(String name, IBinder service) {
+ publishBinderService(name, service, false);
+ }
+
+ /**
+ * Publish the service so it is accessible to other services and apps.
+ */
+ protected final void publishBinderService(String name, IBinder service,
+ boolean allowIsolated) {
+ ServiceManager.addService(name, service, allowIsolated);
+ }
+
+ /**
+ * Get a binder service by its name.
+ */
+ protected final IBinder getBinderService(String name) {
+ return ServiceManager.getService(name);
+ }
+
+ /**
+ * Publish the service so it is only accessible to the system process.
+ */
+ protected final <T> void publishLocalService(Class<T> type, T service) {
+ LocalServices.addService(type, service);
+ }
+
+ /**
+ * Get a local service by interface.
+ */
+ protected final <T> T getLocalService(Class<T> type) {
+ return LocalServices.getService(type);
+ }
+
+ private SystemServiceManager getManager() {
+ return LocalServices.getService(SystemServiceManager.class);
+ }
+
+// /**
+// * Called when a new user has been created. If your service deals with multiple users, this
+// * method should be overridden.
+// *
+// * @param userHandle The user that was created.
+// */
+// public void onUserCreated(int userHandle) {
+// }
+//
+// /**
+// * Called when an existing user has started a new session. If your service deals with multiple
+// * users, this method should be overridden.
+// *
+// * @param userHandle The user who started a new session.
+// */
+// public void onUserStarted(int userHandle) {
+// }
+//
+// /**
+// * Called when a background user session has entered the foreground. If your service deals with
+// * multiple users, this method should be overridden.
+// *
+// * @param userHandle The user who's session entered the foreground.
+// */
+// public void onUserForeground(int userHandle) {
+// }
+//
+// /**
+// * Called when a foreground user session has entered the background. If your service deals with
+// * multiple users, this method should be overridden;
+// *
+// * @param userHandle The user who's session entered the background.
+// */
+// public void onUserBackground(int userHandle) {
+// }
+//
+// /**
+// * Called when a user's active session has stopped. If your service deals with multiple users,
+// * this method should be overridden.
+// *
+// * @param userHandle The user who's session has stopped.
+// */
+// public void onUserStopped(int userHandle) {
+// }
+//
+// /**
+// * Called when a user has been removed from the system. If your service deals with multiple
+// * users, this method should be overridden.
+// *
+// * @param userHandle The user who has been removed.
+// */
+// public void onUserRemoved(int userHandle) {
+// }
+}
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..eb8df0e
--- /dev/null
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,164 @@
+/*
+ * 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 com.android.server;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of
+ * {@link com.android.server.SystemService system services}.
+ *
+ * {@hide}
+ */
+public class SystemServiceManager {
+ private static final String TAG = "SystemServiceManager";
+
+ private final Context mContext;
+ private boolean mSafeMode;
+
+ // Services that should receive lifecycle events.
+ private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+ private int mCurrentPhase = -1;
+
+ public SystemServiceManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Starts a service by class name.
+ *
+ * @return The service instance.
+ */
+ @SuppressWarnings("unchecked")
+ public SystemService startService(String className) throws ClassNotFoundException {
+ return startService((Class<SystemService>) Class.forName(className));
+ }
+
+ /**
+ * Creates and starts a system service. The class must be a subclass of
+ * {@link com.android.server.SystemService}.
+ *
+ * @param serviceClass A Java class that implements the SystemService interface.
+ * @return The service instance, never null.
+ * @throws RuntimeException if the service fails to start.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends SystemService> T startService(Class<T> serviceClass) {
+ final String name = serviceClass.getName();
+ Slog.i(TAG, "Starting " + name);
+
+ // Create the service.
+ if (!SystemService.class.isAssignableFrom(serviceClass)) {
+ throw new RuntimeException("Failed to create " + name
+ + ": service must extend " + SystemService.class.getName());
+ }
+ final T service;
+ try {
+ Constructor<T> constructor = serviceClass.getConstructor(Context.class);
+ service = constructor.newInstance(mContext);
+ } catch (InstantiationException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service could not be instantiated", ex);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (InvocationTargetException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service constructor threw an exception", ex);
+ }
+
+ // Register it.
+ mServices.add(service);
+
+ // Start it.
+ try {
+ service.onStart();
+ } catch (RuntimeException ex) {
+ throw new RuntimeException("Failed to start service " + name
+ + ": onStart threw an exception", ex);
+ }
+ return service;
+ }
+
+ /**
+ * Starts the specified boot phase for all system services that have been started up to
+ * this point.
+ *
+ * @param phase The boot phase to start.
+ */
+ public void startBootPhase(final int phase) {
+ if (phase <= mCurrentPhase) {
+ throw new IllegalArgumentException("Next phase must be larger than previous");
+ }
+ mCurrentPhase = phase;
+
+ Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onBootPhase(mCurrentPhase);
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to boot service "
+ + service.getClass().getName()
+ + ": onBootPhase threw an exception during phase "
+ + mCurrentPhase, ex);
+ }
+ }
+ }
+
+ /** Sets the safe mode flag for services to query. */
+ public void setSafeMode(boolean safeMode) {
+ mSafeMode = safeMode;
+ }
+
+ /**
+ * Returns whether we are booting into safe mode.
+ * @return safe mode flag
+ */
+ public boolean isSafeMode() {
+ return mSafeMode;
+ }
+
+ /**
+ * Outputs the state of this manager to the System log.
+ */
+ public void dump() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+ builder.append("Services:\n");
+ final int startedLen = mServices.size();
+ for (int i = 0; i < startedLen; i++) {
+ final SystemService service = mServices.get(i);
+ builder.append("\t")
+ .append(service.getClass().getSimpleName())
+ .append("\n");
+ }
+
+ Slog.e(TAG, builder.toString());
+ }
+}