Merge "Create new windows on *other* side in multi-window mode."
diff --git a/Android.mk b/Android.mk
index 5983b30..52ed634 100644
--- a/Android.mk
+++ b/Android.mk
@@ -187,6 +187,8 @@
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
+ core/java/android/hardware/location/IContextHubCallback.aidl \
+ core/java/android/hardware/location/IContextHubService.aidl \
core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/ICaptivePortal.aidl \
diff --git a/api/current.txt b/api/current.txt
index aa503af1..f13601e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29592,6 +29592,8 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -32042,6 +32044,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
diff --git a/api/system-current.txt b/api/system-current.txt
index 95c19d7..0d33503 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9956,6 +9956,7 @@
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
@@ -15123,6 +15124,66 @@
package android.hardware.location {
+ public class ContextHubInfo {
+ ctor public ContextHubInfo();
+ method public int describeContents();
+ method public int getId();
+ method public android.hardware.location.MemoryRegion[] getMemoryRegions();
+ method public java.lang.String getName();
+ method public float getPeakMips();
+ method public float getPeakPowerDrawMw();
+ method public int getPlatformVersion();
+ method public float getSleepPowerDrawMw();
+ method public int getStaticSwVersion();
+ method public float getStoppedPowerDrawMw();
+ method public int[] getSupportedSensors();
+ method public java.lang.String getToolchain();
+ method public int getToolchainVersion();
+ method public java.lang.String getVendor();
+ method public void setId(int);
+ method public void setMemoryRegions(android.hardware.location.MemoryRegion[]);
+ method public void setName(java.lang.String);
+ method public void setPeakMips(float);
+ method public void setPeakPowerDrawMw(float);
+ method public void setPlatformVersion(int);
+ method public void setSleepPowerDrawMw(float);
+ method public void setStaticSwVersion(int);
+ method public void setStoppedPowerDrawMw(float);
+ method public void setSupportedSensors(int[]);
+ method public void setToolchain(java.lang.String);
+ method public void setToolchainVersion(int);
+ method public void setVendor(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
+ }
+
+ public final class ContextHubManager {
+ method public java.lang.Integer[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+ method public int[] getContexthubHandles();
+ method public android.hardware.location.ContextHubInfo getContexthubInfo(int);
+ method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+ method public int loadNanoApp(int, android.hardware.location.NanoApp);
+ method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
+ method public int unloadNanoApp(int);
+ field public static final int ANY_HUB = -1; // 0xffffffff
+ field public static final int MSG_DATA_SEND = 3; // 0x3
+ field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
+ field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
+ }
+
+ public class ContextHubMessage {
+ ctor public ContextHubMessage(int, int, byte[]);
+ method public int describeContents();
+ method public byte[] getData();
+ method public int getMsgType();
+ method public int getVersion();
+ method public void setMsgData(byte[]);
+ method public void setMsgType(int);
+ method public void setVersion(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
+ }
+
public final class GeofenceHardware {
ctor public GeofenceHardware(android.hardware.location.IGeofenceHardware);
method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
@@ -15239,6 +15300,89 @@
method public abstract void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent) throws android.os.RemoteException;
}
+ public class MemoryRegion implements android.os.Parcelable {
+ ctor public MemoryRegion(android.os.Parcel);
+ method public int describeContents();
+ method public int getCapacityBytes();
+ method public int getFreeCapacityBytes();
+ method public boolean isExecutable();
+ method public boolean isReadable();
+ method public boolean isWritable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
+ }
+
+ public class NanoApp {
+ ctor public NanoApp();
+ method public int describeContents();
+ method public byte[] getAppBinary();
+ method public int getAppId();
+ method public int getAppVersion();
+ method public java.lang.String getName();
+ method public int getNeededExecMemBytes();
+ method public int getNeededReadMemBytes();
+ method public int[] getNeededSensors();
+ method public int getNeededWriteMemBytes();
+ method public int[] getOutputEvents();
+ method public java.lang.String getPublisher();
+ method public void setAppBinary(byte[]);
+ method public void setAppId(int);
+ method public void setAppVersion(int);
+ method public void setName(java.lang.String);
+ method public void setNeededExecMemBytes(int);
+ method public void setNeededReadMemBytes(int);
+ method public void setNeededSensors(int[]);
+ method public void setNeededWriteMemBytes(int);
+ method public void setOutputEvents(int[]);
+ method public void setPublisher(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
+ }
+
+ public class NanoAppFilter {
+ ctor public NanoAppFilter(long, int, int, long);
+ method public int describeContents();
+ method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int APP_ANY = -1; // 0xffffffff
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
+ field public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
+ field public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
+ field public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
+ field public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
+ field public static final int HUB_ANY = -1; // 0xffffffff
+ field public static final int VENDOR_ANY = -1; // 0xffffffff
+ }
+
+ public class NanoAppInstanceInfo {
+ ctor public NanoAppInstanceInfo();
+ method public int describeContents();
+ method public int getAppId();
+ method public int getAppVersion();
+ method public int getContexthubId();
+ method public int getHandle();
+ method public java.lang.String getName();
+ method public int getNeededExecMemBytes();
+ method public int getNeededReadMemBytes();
+ method public int[] getNeededSensors();
+ method public int getNeededWriteMemBytes();
+ method public int[] getOutputEvents();
+ method public java.lang.String getPublisher();
+ method public void setAppId(int);
+ method public void setAppVersion(int);
+ method public void setContexthubId(int);
+ method public void setHandle(int);
+ method public void setName(java.lang.String);
+ method public void setNeededExecMemBytes(int);
+ method public void setNeededReadMemBytes(int);
+ method public void setNeededSensors(int[]);
+ method public void setNeededWriteMemBytes(int);
+ method public void setOutputEvents(int[]);
+ method public void setPublisher(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
+ }
+
}
package android.hardware.radio {
@@ -31062,6 +31206,7 @@
method public deprecated boolean isOwner();
method public boolean isSystem();
method public static int myUserId();
+ method public static android.os.UserHandle of(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -31076,6 +31221,7 @@
method public android.os.PersistableBundle getSeedAccountOptions();
method public java.lang.String getSeedAccountType();
method public long getSerialNumberForUser(android.os.UserHandle);
+ method public long[] getSerialNumbersOfUsers(boolean);
method public int getUserCount();
method public long getUserCreationTime(android.os.UserHandle);
method public android.os.UserHandle getUserForSerialNumber(long);
@@ -31493,6 +31639,9 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageCredentialEncrypted();
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -34075,6 +34224,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
diff --git a/api/test-current.txt b/api/test-current.txt
index 081c471..48fd6f0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -29602,6 +29602,8 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -32055,6 +32057,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8bc17f8..be93926 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -49,7 +49,8 @@
import java.util.List;
/**
- * An accessibility service runs in the background and receives callbacks by the system
+ * Accessibility services are intended to assist users with disabilities in using
+ * Android devices and apps. They run in the background and receive callbacks by the system
* when {@link AccessibilityEvent}s are fired. Such events denote some state transition
* in the user interface, for example, the focus has changed, a button has been clicked,
* etc. Such a service can optionally request the capability for querying the content
@@ -66,22 +67,31 @@
* <h3>Lifecycle</h3>
* <p>
* The lifecycle of an accessibility service is managed exclusively by the system and
- * follows the established service life cycle. Additionally, starting or stopping an
- * accessibility service is triggered exclusively by an explicit user action through
- * enabling or disabling it in the device settings. After the system binds to a service it
- * calls {@link AccessibilityService#onServiceConnected()}. This method can be
- * overriden by clients that want to perform post binding setup.
+ * follows the established service life cycle. Starting an accessibility service is triggered
+ * exclusively by the user explicitly turning the service on in device settings. After the system
+ * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
+ * be overriden by clients that want to perform post binding setup.
+ * </p>
+ * <p>
+ * An accessibility service stops either when the user turns it off in device settings or when
+ * it calls {@link AccessibilityService#disableSelf()}.
* </p>
* <h3>Declaration</h3>
* <p>
- * An accessibility is declared as any other service in an AndroidManifest.xml but it
- * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
- * {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Additionally an accessibility service must request the
- * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
- * that only the system
- * can bind to it. Failure to declare this intent will cause the system to ignore the
- * accessibility service. Following is an example declaration:
+ * An accessibility is declared as any other service in an AndroidManifest.xml, but it
+ * must do two things:
+ * <ul>
+ * <ol>
+ * Specify that it handles the "android.accessibilityservice.AccessibilityService"
+ * {@link android.content.Intent}.
+ * </ol>
+ * <ol>
+ * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
+ * ensure that only the system can bind to it.
+ * </ol>
+ * </ul>
+ * If either of these items is missing, the system will ignore the accessibility service.
+ * Following is an example declaration:
* </p>
* <pre> <service android:name=".MyAccessibilityService"
* android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
@@ -135,48 +145,24 @@
* </ul>
* <h3>Retrieving window content</h3>
* <p>
- * A service can specify in its declaration that it can retrieve the active window
- * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
+ * A service can specify in its declaration that it can retrieve window
+ * content which is represented as a tree of {@link AccessibilityWindowInfo} and
+ * {@link AccessibilityNodeInfo} objects. Note that
* declaring this capability requires that the service declares its configuration via
* an XML resource referenced by {@link #SERVICE_META_DATA}.
* </p>
* <p>
- * For security purposes an accessibility service can retrieve only the content of the
- * currently active window. The currently active window is defined as the window from
- * which was fired the last event of the following types:
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * In other words, the last window that was shown or the last window that the user has touched
- * during touch exploration.
- * </p>
- * <p>
- * The entry point for retrieving window content is through calling
- * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
- * event of the above types or a previous event from the same window
- * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
- * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
- * window content which represented as a tree of such objects.
+ * Window content may be retrieved with
+ * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
+ * {@link AccessibilityService#findFocus(int)},
+ * {@link AccessibilityService#getWindows()}, or
+ * {@link AccessibilityService#getRootInActiveWindow()}.
* </p>
* <p class="note">
* <strong>Note</strong> An accessibility service may have requested to be notified for
- * a subset of the event types, thus be unaware that the active window has changed. Therefore
- * accessibility service that would like to retrieve window content should:
- * <ul>
- * <li>
- * Register for all event types with no notification timeout and keep track for the active
- * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
- * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
- * methods on the latter.
- * </li>
- * <li>
- * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
- * active window has changed and the service did not get the accessibility event yet. Note
- * that it is possible to have a retrieval method failing even adopting the strategy
- * specified in the previous bullet because the accessibility event dispatch is asynchronous
- * and crosses process boundaries.
- * </li>
- * </ul>
+ * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
+ * possible for a node to contain outdated information because the window content may change at any
+ * time.
* </p>
* <h3>Notification strategy</h3>
* <p>
@@ -328,7 +314,6 @@
* android:settingsActivity="foo.bar.TestBackActivity"
* android:canRetrieveWindowContent="true"
* android:canRequestTouchExplorationMode="true"
- * android:canRequestEnhancedWebAccessibility="true"
* . . .
* /></pre>
*/
@@ -528,6 +513,14 @@
* is currently touching or the window with input focus, if the user is not
* touching any window.
* <p>
+ * The currently active window is defined as the window that most recently fired one
+ * of the following events:
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
+ * In other words, the last window shown that also has input focus.
+ * </p>
+ * <p>
* <strong>Note:</strong> In order to access the root node your service has
* to declare the capability to retrieve window content by setting the
* {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
@@ -541,8 +534,8 @@
}
/**
- * This method allows accessibility service turn itself off
- * and the service will become disabled from the Settings.
+ * Disables the service. After calling this method, the service will be disabled and settings
+ * will show that it is turned off.
*/
public final void disableSelf() {
final IAccessibilityServiceConnection connection =
@@ -1054,7 +1047,7 @@
* property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
* Also the service has to opt-in to retrieve the interactive windows by
* setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
- * flag.Otherwise, the search will be performed only in the active window.
+ * flag. Otherwise, the search will be performed only in the active window.
* </p>
*
* @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0fce4e2..a88aa3125 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -165,14 +165,18 @@
mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
}
- if (right.mEndTimeStamp > mEndTimeStamp) {
+ if (right.mBeginTimeStamp > mBeginTimeStamp) {
+ // The incoming UsageStat begins after this one, so use its last time used fields
+ // as the source of truth.
+ // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+ // regards to their mEndTimeStamp.
mLastEvent = right.mLastEvent;
- mEndTimeStamp = right.mEndTimeStamp;
mLastTimeUsed = right.mLastTimeUsed;
mBeginIdleTime = right.mBeginIdleTime;
mLastTimeSystemUsed = right.mLastTimeSystemUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
+ mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
mLaunchCount += right.mLaunchCount;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index aaa02bd..3a94bf7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3632,7 +3632,7 @@
* {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
* {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
* to modify the data returned.
- * @param userId The userId of the user being queried.
+ * @param userHandle UserHandle of the user being queried.
*
* @return Returns a List of ResolveInfo objects containing one entry for each
* matching receiver, ordered from best to worst. If there are no matching
@@ -3653,9 +3653,19 @@
*
* @hide
*/
+ @SystemApi
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ @ResolveInfoFlags int flags, UserHandle userHandle) {
+ return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
+ }
+
+ /**
+ * @hide
+ */
public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
+
/** {@hide} */
@Deprecated
public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9319c2e..44cd003 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3491,6 +3491,7 @@
info.maxRecents = target.info.maxRecents;
info.layout = target.info.layout;
info.resizeMode = target.info.resizeMode;
+ info.encryptionAware = target.info.encryptionAware;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
diff --git a/core/java/android/hardware/location/ContextHubInfo.aidl b/core/java/android/hardware/location/ContextHubInfo.aidl
new file mode 100644
index 0000000..1a9221a
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.location;
+/*
+@hide
+*/
+parcelable ContextHubInfo;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
new file mode 100644
index 0000000..e47c541
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubInfo {
+ private int mId;
+ private String mName;
+ private String mVendor;
+ private String mToolchain;
+ private int mPlatformVersion;
+ private int mStaticSwVersion;
+ private int mToolchainVersion;
+ private float mPeakMips;
+ private float mStoppedPowerDrawMw;
+ private float mSleepPowerDrawMw;
+ private float mPeakPowerDrawMw;
+
+ private int[] mSupportedSensors;
+
+ private MemoryRegion[] mMemoryRegions;
+
+ public ContextHubInfo() {
+ }
+
+ /**
+ * get the context hub unique identifer
+ *
+ * @return int - unique system wide identifier
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * set the context hub unique identifer
+ *
+ * @param id - unique system wide identifier for the hub
+ */
+ public void setId(int id) {
+ mId = id;
+ }
+
+ /**
+ * get a string as a hub name
+ *
+ * @return String - a name for the hub
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * set a string as the hub name
+ *
+ * @param String - the name for the hub
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * get a string as the vendor name
+ *
+ * @return String - a name for the vendor
+ */
+ public String getVendor() {
+ return mVendor;
+ }
+
+ /**
+ * set a string as the vendor name
+ *
+ * @param String - a name for the vendor
+ */
+ public void setVendor(String vendor) {
+ mVendor = vendor;
+ }
+
+ /**
+ * get tool chain string
+ *
+ * @return String - description of the tool chain
+ */
+ public String getToolchain() {
+ return mToolchain;
+ }
+
+ /**
+ * set tool chain string
+ *
+ * @param String - description of the tool chain
+ */
+ public void setToolchain(String toolchain) {
+ mToolchain = toolchain;
+ }
+
+ /**
+ * get platform version
+ *
+ * @return int - platform version number
+ */
+ public int getPlatformVersion() {
+ return mPlatformVersion;
+ }
+
+ /**
+ * set platform version
+ *
+ * @param platformVersion - platform version number
+ */
+ public void setPlatformVersion(int platformVersion) {
+ mPlatformVersion = platformVersion;
+ }
+
+ /**
+ * get static platform version number
+ *
+ * @return int - platform version number
+ */
+ public int getStaticSwVersion() {
+ return mStaticSwVersion;
+ }
+
+ /**
+ * set platform software version
+ *
+ * @param staticSwVersion - platform static s/w version number
+ */
+ public void setStaticSwVersion(int staticSwVersion) {
+ mStaticSwVersion = staticSwVersion;
+ }
+
+ /**
+ * get the tool chain version
+ *
+ * @return int - the tool chain version
+ */
+ public int getToolchainVersion() {
+ return mToolchainVersion;
+ }
+
+ /**
+ * set the tool chain version number
+ *
+ * @param toolchainVersion - tool chain version number
+ */
+ public void setToolchainVersion(int toolchainVersion) {
+ mToolchainVersion = toolchainVersion;
+ }
+
+ /**
+ * get the peak processing mips the hub can support
+ *
+ * @return float - peak MIPS that this hub can deliver
+ */
+ public float getPeakMips() {
+ return mPeakMips;
+ }
+
+ /**
+ * set the peak mips that this hub can support
+ *
+ * @param peakMips - peak mips this hub can deliver
+ */
+ public void setPeakMips(float peakMips) {
+ mPeakMips = peakMips;
+ }
+
+ /**
+ * get the stopped power draw in milliwatts
+ * This assumes that the hub enter a stopped state - which is
+ * different from the sleep state. Latencies on exiting the
+ * sleep state are typically higher and expect to be in multiple
+ * milliseconds.
+ *
+ * @return float - power draw by the hub in stopped state
+ */
+ public float getStoppedPowerDrawMw() {
+ return mStoppedPowerDrawMw;
+ }
+
+ /**
+ * Set the power consumed by the hub in stopped state
+ *
+ * @param stoppedPowerDrawMw - stopped power in milli watts
+ */
+ public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
+ mStoppedPowerDrawMw = stoppedPowerDrawMw;
+ }
+
+ /**
+ * get the power draw of the hub in sleep mode. This assumes
+ * that the hub supports a sleep mode in which the power draw is
+ * lower than the power consumed when the hub is actively
+ * processing. As a guideline, assume that the hub should be
+ * able to enter sleep mode if it knows reliably on completion
+ * of some task that the next interrupt/scheduled work item is
+ * at least 250 milliseconds later.
+ *
+ * @return float - sleep power draw in milli watts
+ */
+ public float getSleepPowerDrawMw() {
+ return mSleepPowerDrawMw;
+ }
+
+ /**
+ * Set the sleep power draw in milliwatts
+ *
+ * @param sleepPowerDrawMw - sleep power draw in milliwatts.
+ */
+ public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
+ mSleepPowerDrawMw = sleepPowerDrawMw;
+ }
+
+ /**
+ * get the peak powe draw of the hub. This is the power consumed
+ * by the hub at maximum load.
+ *
+ * @return float - peak power draw
+ */
+ public float getPeakPowerDrawMw() {
+ return mPeakPowerDrawMw;
+ }
+
+ /**
+ * set the peak power draw of the hub
+ *
+ * @param peakPowerDrawMw - peak power draw of the hub in
+ * milliwatts.
+ */
+ public void setPeakPowerDrawMw(float peakPowerDrawMw) {
+ mPeakPowerDrawMw = peakPowerDrawMw;
+ }
+
+ /**
+ * get the sensors supported by this hub
+ *
+ * @return int[] - all the supported sensors on this hub
+ *
+ * @see ContextHubManager
+ */
+ public int[] getSupportedSensors() {
+ return Arrays.copyOf(mSupportedSensors, mSupportedSensors.length);
+ }
+
+ /**
+ * get the various memory regions on this hub
+ *
+ * @return MemoryRegion[] - all the memory regions on this hub
+ *
+ * @see MemoryRegion
+ */
+ public MemoryRegion[] getMemoryRegions() {
+ return Arrays.copyOf(mMemoryRegions, mMemoryRegions.length);
+ }
+
+ /**
+ * set the supported sensors on this hub
+ *
+ * @param supportedSensors - supported sensors on this hub
+ */
+ public void setSupportedSensors(int[] supportedSensors) {
+ mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
+ }
+
+ /**
+ * set memory regions for this hub
+ *
+ * @param memoryRegions - memory regions information
+ *
+ * @see MemoryRegion
+ */
+ public void setMemoryRegions(MemoryRegion[] memoryRegions) {
+ mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
+ }
+
+ private ContextHubInfo(Parcel in) {
+ mId = in.readInt();
+ mName = in.readString();
+ mVendor = in.readString();
+ mToolchain = in.readString();
+ mPlatformVersion = in.readInt();
+ mToolchainVersion = in.readInt();
+ mStaticSwVersion = in.readInt();
+ mPeakMips = in.readFloat();
+ mStoppedPowerDrawMw = in.readFloat();
+ mSleepPowerDrawMw = in.readFloat();
+ mPeakPowerDrawMw = in.readFloat();
+
+ int numSupportedSensors = in.readInt();
+ mSupportedSensors = new int[numSupportedSensors];
+ in.readIntArray(mSupportedSensors);
+ mMemoryRegions = in.createTypedArray(MemoryRegion.CREATOR);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeString(mName);
+ out.writeString(mVendor);
+ out.writeString(mToolchain);
+ out.writeInt(mPlatformVersion);
+ out.writeInt(mToolchainVersion);
+ out.writeInt(mStaticSwVersion);
+ out.writeFloat(mPeakMips);
+ out.writeFloat(mStoppedPowerDrawMw);
+ out.writeFloat(mSleepPowerDrawMw);
+ out.writeFloat(mPeakPowerDrawMw);
+
+ out.writeInt(mSupportedSensors.length);
+ out.writeIntArray(mSupportedSensors);
+ out.writeTypedArray(mMemoryRegions, flags);
+ }
+
+ public static final Parcelable.Creator<ContextHubInfo> CREATOR
+ = new Parcelable.Creator<ContextHubInfo>() {
+ public ContextHubInfo createFromParcel(Parcel in) {
+ return new ContextHubInfo(in);
+ }
+
+ public ContextHubInfo[] newArray(int size) {
+ return new ContextHubInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
new file mode 100644
index 0000000..301b2e4
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+import android.annotation.SystemApi;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.Manifest;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A class that exposes the Context hubs on a device to
+ * applicaions.
+ *
+ * Please not that this class is not expected to be used by
+ * unbundled applications. Also, calling applications are
+ * expected to have LOCTION_HARDWARE premissions to use this
+ * class.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContextHubManager {
+
+ private static final String TAG = "ContextHubManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+ private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
+
+ private Context mContext;
+ private IContextHubService mContextHubService;
+ private boolean mContextHubConnected;
+
+ /**
+ * A special context hub identifer meaning any possible hub on
+ * the system.
+ */
+ public static final int ANY_HUB = -1;
+ /**
+ * A constant denoting a message to load a a Nano App
+ */
+ public static final int MSG_LOAD_NANO_APP = 1;
+ /**
+ * A constant denoting a message to unload a a Nano App
+ */
+ public static final int MSG_UNLOAD_NANO_APP = 2;
+ /**
+ * A constant denoting a message to send a message
+ */
+ public static final int MSG_DATA_SEND = 3;
+
+
+ /**
+ * Get a handle to all the context hubs in the system
+ * @return array of context hub handles
+ */
+ public int[] getContexthubHandles() {
+ int[] retVal = null;
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getContextHubHandles();
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch context hub handles :" + e.toString());
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * Get more information about a specific hub.
+ *
+ * @param contexthubHandle Handle of context hub
+ *
+ * @return ContextHubInfo returned information about the hub
+ *
+ * @see ContextHubInfo
+ */
+ public ContextHubInfo getContexthubInfo(int contexthubHandle) {
+ ContextHubInfo retVal = null;
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getContextHubInfo(contexthubHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch context hub info :" + e.toString());
+ }
+ }
+
+ return(retVal);
+ }
+
+ /**
+ * Load a nanoapp on a specified context hub
+ *
+ * @param hubHandle handle of context hub to load the app on.
+ * @param app the nanoApp to load on the hub
+ *
+ * @return int nanoAppInstance of the loaded nanoApp on success,
+ * -1 otherwise
+ *
+ * @see NanoApp
+ */
+ public int loadNanoApp(int hubHandle, NanoApp app) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.loadNanoApp(hubHandle, app);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch load nanoApp :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Unload a specified nanoApp
+ *
+ * @param nanoAppInstanceHandle handle of the nanoApp to load
+ *
+ * @return int 0 on success, -1 otherewise
+ */
+ public int unloadNanoApp(int nanoAppInstanceHandle) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.unloadNanoApp(nanoAppInstanceHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch unload nanoApp :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * get information about the nano app instance
+ *
+ * @param nanoAppInstanceHandle handle of the nanoAppInstance
+ *
+ * @return NanoAppInstanceInfo Inforamtion about the nano app
+ * instance.
+ *
+ * @see NanoAppInstanceInfo
+ */
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+ NanoAppInstanceInfo retVal = null;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getNanoAppInstanceInfo(nanoAppInstanceHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch nanoApp info :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Find a specified nano app on the system
+ *
+ * @param hubHandle handle of hub to search for nano app
+ * @param filter filter specifying the search criteria for app
+ *
+ * @see NanoAppFilter
+ *
+ * @return Integer[] Array of handles to any found nano apps
+ */
+ public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+ int[] temp;
+ Integer[] retVal = null;
+
+ if(mContextHubConnected) {
+ try {
+ temp = mContextHubService.findNanoAppOnHub(hubHandle, filter);
+ retVal = new Integer[temp.length];
+ for (int i = 0; i < temp.length; i++) {
+ retVal[i] = temp[i];
+ }
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not query nanoApp instance :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Send a message to a spcific nano app instance on a context
+ * hub
+ *
+ *
+ * @param hubHandle handle of the hub to send the message to
+ * @param nanoAppHandle handle of the nano app to send to
+ * @param msg Message to be sent
+ *
+ * @see ContextHubMessage
+ *
+ * @return int 0 on success, -1 otherwise
+ */
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.sendMessage(hubHandle, nanoAppHandle, msg);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch send message :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ private void checkPermissions() {
+ mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ }
+
+ private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
+ @Override
+ public void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg) throws RemoteException {
+
+ }
+ };
+
+ private ContextHubManager(Context context) {
+ checkPermissions();
+ mContext = context;
+ mContextHubConnected = false;
+ }
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mContextHubService = IContextHubService.Stub.asInterface(service);
+ mContextHubConnected = true;
+
+ // Register our Callback
+ try {
+ mContextHubService.registerCallBack(mClientCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not register callback with context hub service :" + e.toString());
+ }
+ Log.d(TAG, "contexthub manager connected to " + name.toString());
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mContextHubService = null;
+ mContextHubConnected = false;
+ Log.d(TAG, "contexthub manager disconnected from " + name.toString());
+ }
+ };
+
+}
diff --git a/core/java/android/hardware/location/ContextHubMessage.aidl b/core/java/android/hardware/location/ContextHubMessage.aidl
new file mode 100644
index 0000000..915f1ec
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 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.location;
+/*
+@hide
+*/
+parcelable ContextHubMessage;
+
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
new file mode 100644
index 0000000..954e97d
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubMessage {
+ private int mType;
+ private int mVersion;
+ private byte[]mData;
+
+ /**
+ * Get the message type
+ *
+ * @return int - message type
+ */
+ public int getMsgType() {
+ return mType;
+ }
+
+ /**
+ * get message version
+ *
+ * @return int - message version
+ */
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * get message data
+ *
+ * @return byte[] - message data buffer
+ */
+ public byte[] getData() {
+ return Arrays.copyOf(mData, mData.length);
+ }
+
+ /**
+ * set message type
+ *
+ * @param msgType - message type
+ */
+ public void setMsgType(int msgType) {
+ mType = msgType;
+ }
+
+ /**
+ * Set message version
+ *
+ * @param version - message version
+ */
+ public void setVersion(int version) {
+ mVersion = version;
+ }
+
+ /**
+ * set message data
+ *
+ * @param data - message buffer
+ */
+ public void setMsgData(byte[] data) {
+ mData = Arrays.copyOf(data, data.length);
+ }
+
+ /**
+ * Constructor for a context hub message
+ *
+ * @param msgType - message type
+ * @param version - version
+ * @param data - message buffer
+ */
+ public ContextHubMessage(int msgType, int version, byte[] data) {
+ mType = msgType;
+ mVersion = version;
+ mData = Arrays.copyOf(data, data.length);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ private ContextHubMessage(Parcel in) {
+ mType = in.readInt();
+ mVersion = in.readInt();
+ byte[] byteBuffer = new byte[in.readInt()];
+ in.readByteArray(byteBuffer);
+ }
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mType);
+ out.writeInt(mVersion);
+ out.writeInt(mData.length);
+ out.writeByteArray(mData);
+ }
+
+ public static final Parcelable.Creator<ContextHubMessage> CREATOR
+ = new Parcelable.Creator<ContextHubMessage>() {
+ public ContextHubMessage createFromParcel(Parcel in) {
+ return new ContextHubMessage(in);
+ }
+
+ public ContextHubMessage[] newArray(int size) {
+ return new ContextHubMessage[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
new file mode 100644
index 0000000..a2a13c6
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class ContextHubService extends Service {
+
+ private static final String TAG = "ContextHubService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static ContextHubService sSingletonInstance;
+ private static final Object sSingletonInstanceLock = new Object();
+
+ private HashMap<Integer, ContextHubInfo> mHubHash;
+ private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
+ private ContextHubInfo[] mContexthubInfo;
+
+
+ private native int nativeSendMessage(int[] header, byte[] data);
+ private native ContextHubInfo[] nativeInitialize();
+
+ private int onMessageReceipt(int[] header, byte[] data) {
+ return 0;
+ }
+ private void initialize() {
+ mContexthubInfo = nativeInitialize();
+
+ mHubHash = new HashMap<Integer, ContextHubInfo>();
+
+ for (int i = 0; i < mContexthubInfo.length; i++) {
+ mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
+ }
+ }
+
+ private ContextHubService(Context context) {
+ initialize();
+ Log.d(TAG, "Created from " + context.toString());
+ }
+
+ public static ContextHubService getInstance(Context context) {
+ synchronized (sSingletonInstanceLock) {
+ if (sSingletonInstance == null) {
+ sSingletonInstance = new ContextHubService(context);
+ }
+ return sSingletonInstance;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
+
+ private IContextHubCallback callback;
+
+ @Override
+ public int registerCallBack(IContextHubCallback callback) throws RemoteException{
+ this.callback = callback;
+ return 0;
+ }
+
+ @Override
+ public int[] getContextHubHandles() throws RemoteException {
+ int [] returnArray = new int[mHubHash.size()];
+ int i = 0;
+ for (int key : mHubHash.keySet()) {
+ // Add any filtering here
+ returnArray[i] = key;
+ i++;
+ }
+ return returnArray;
+ }
+
+ @Override
+ public ContextHubInfo getContextHubInfo(int contexthubHandle) throws RemoteException {
+ return mHubHash.get(contexthubHandle);
+ }
+
+ @Override
+ public int loadNanoApp(int hubHandle, NanoApp app) throws RemoteException {
+ if (!mHubHash.containsKey(hubHandle)) {
+ return -1;
+ } else {
+ // Call Native interface here
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_LOAD_NANO_APP;
+ msgHeader[1] = app.getAppId();
+ msgHeader[2] = app.getAppVersion();
+ msgHeader[3] = 0; // LOADING_HINTS
+ msgHeader[4] = hubHandle;
+
+ int handle = nativeSendMessage(msgHeader, app.getAppBinary());
+
+ // if successful, add an entry to mNanoAppHash
+
+ if(handle > 0) {
+ return 0;
+ } else {
+
+ return -1;
+ }
+ }
+ }
+
+ @Override
+ public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+ if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+ return -1;
+ } else {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+ // Call Native interface here
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_UNLOAD_NANO_APP;
+ msgHeader[1] = info.getContexthubId();
+ msgHeader[2] = info.getHandle();
+
+ int result = nativeSendMessage(msgHeader, null);
+ // if successful, remove the entry in mNanoAppHash
+ if(result == 0) {
+ mNanoAppHash.remove(nanoAppInstanceHandle);
+ }
+ return(result);
+ }
+ }
+
+ @Override
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
+ // This assumes that all the nanoAppInfo is current. This is reasonable
+ // for the use cases for tightly controlled nanoApps.
+ //
+ if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+ return(mNanoAppHash.get(nanoAppInstanceHandle));
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+ ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+
+ for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+
+ if(filter.testMatch(info)){
+ foundInstances.add(nanoAppInstance);
+ }
+ }
+
+ int[] retArray = new int[foundInstances.size()];
+ for (int i = 0; i < foundInstances.size(); i++) {
+ retArray[i] = foundInstances.get(i).intValue();
+ }
+
+ return retArray;
+ }
+
+ @Override
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
+ msgHeader[1] = hubHandle;
+ msgHeader[2] = nanoAppHandle;
+ msgHeader[3] = msg.getMsgType();
+ msgHeader[4] = msg.getVersion();
+
+ return (nativeSendMessage(msgHeader, msg.getData()));
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/IContextHubCallback.aidl b/core/java/android/hardware/location/IContextHubCallback.aidl
new file mode 100644
index 0000000..45b1ef4
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+import android.hardware.location.ContextHubMessage;
+
+/** @hide */
+oneway interface IContextHubCallback {
+ void onMessageReceipt(int hubId, int nanoAppId, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
new file mode 100644
index 0000000..b2db0b2
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+// Declare any non-default types here with import statements
+import android.hardware.location.ContextHubMessage;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.IContextHubCallback;
+
+/** @hide */
+interface IContextHubService {
+
+ // register a callback to receive messages
+ int registerCallBack(in IContextHubCallback callback);
+
+ // Gets a list of available context hub handles
+ int[] getContextHubHandles();
+
+ // Get the properties of a hub
+ ContextHubInfo getContextHubInfo(int contextHubHandle);
+
+ // Load a nanoapp on a specified context hub
+ int loadNanoApp(int hubHandle, in NanoApp app);
+
+ // Unload a nanoapp instance
+ int unloadNanoApp(int nanoAppInstanceHandle);
+
+ // get information about a nanoAppInstance
+ NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
+
+ // find all nanoApp instances matching some filter
+ int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
+
+ // send a message to a nanoApp
+ int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
new file mode 100644
index 0000000..e8c7615
--- /dev/null
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+
+@SystemApi
+public class MemoryRegion implements Parcelable{
+
+ private int mSizeBytes;
+ private int mSizeBytesFree;
+ private boolean mIsReadable;
+ private boolean mIsWritable;
+ private boolean mIsExecutable;
+
+ /**
+ * get the capacity of the memory region in bytes
+ *
+ * @return int - the memory capacity in bytes
+ */
+ public int getCapacityBytes() {
+ return mSizeBytes;
+ }
+
+ /**
+ * get the free capacity of the memory region in bytes
+ *
+ * @return int - free bytes
+ */
+ public int getFreeCapacityBytes() {
+ return mSizeBytesFree;
+ }
+
+ /**
+ * Is the memory readable
+ *
+ * @return boolean - true if memory is readable, false otherwise
+ */
+ public boolean isReadable() {
+ return mIsReadable;
+ }
+
+ /**
+ * Is the memory writable
+ *
+ * @return boolean - true if memory is writable, false otherwise
+ */
+ public boolean isWritable() {
+ return mIsWritable;
+ }
+
+ /**
+ * Is the memory executable
+ *
+ * @return boolean - true if memory is executable, false
+ * otherwise
+ */
+ public boolean isExecutable() {
+ return mIsExecutable;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSizeBytes);
+ dest.writeInt(mSizeBytesFree);
+ dest.writeInt(mIsReadable ? 1 : 0);
+ dest.writeInt(mIsWritable ? 1 : 0);
+ dest.writeInt(mIsExecutable ? 1 : 0);
+ }
+
+ public MemoryRegion(Parcel source) {
+ mSizeBytes = source.readInt();
+ mSizeBytesFree = source.readInt();
+ mIsReadable = source.readInt() != 0;
+ mIsWritable = source.readInt() != 0;
+ mIsExecutable = source.readInt() != 0;
+ }
+
+ public static final Parcelable.Creator<MemoryRegion> CREATOR
+ = new Parcelable.Creator<MemoryRegion>() {
+ public MemoryRegion createFromParcel(Parcel in) {
+ return new MemoryRegion(in);
+ }
+
+ public MemoryRegion[] newArray(int size) {
+ return new MemoryRegion[size];
+ }
+ };
+
+}
diff --git a/core/java/android/hardware/location/NanoApp.aidl b/core/java/android/hardware/location/NanoApp.aidl
new file mode 100644
index 0000000..d32c44a
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.location;
+/*
+@hide
+*/
+parcelable NanoApp;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
new file mode 100644
index 0000000..36d181f
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class describing nano apps.
+ * A nano app is a piece of executable code that can be
+ * downloaded onto a specific architecture. These are targtted
+ * for low power compute domains on a device.
+ *
+ * Nano apps are expected to be used only by bundled apps only
+ * at this time.
+ *
+ * @hide
+ */
+@SystemApi
+public class NanoApp {
+ private String mPublisher;
+ private String mName;
+
+ private int mAppId;
+ private int mAppVersion;
+
+ private int mNeededReadMemBytes;
+ private int mNeededWriteMemBytes;
+ private int mNeededExecMemBytes;
+
+ private int[] mNeededSensors;
+ private int[] mOutputEvents;
+ private byte[] mAppBinary;
+
+ public NanoApp() {
+ }
+
+ /**
+ * Set the publisher name
+ *
+ * @param publisher name of the publisher of this nano app
+ */
+ public void setPublisher(String publisher) {
+ mPublisher = publisher;
+ }
+
+ /**
+ * set the name of the app
+ *
+ * @param name name of the app
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * set the app identifier
+ *
+ * @param appId add identifier
+ */
+ public void setAppId(int appId) {
+ mAppId = appId;
+ }
+
+ /**
+ * Set the app version
+ *
+ * @param appVersion app version
+ */
+ public void setAppVersion(int appVersion) {
+ mAppVersion = appVersion;
+ }
+
+ /**
+ * set memory needed as read only
+ *
+ * @param neededReadMemBytes
+ * read only memory needed in bytes
+ */
+ public void setNeededReadMemBytes(int neededReadMemBytes) {
+ mNeededReadMemBytes = neededReadMemBytes;
+ }
+
+ /**
+ * set writable memory needed in bytes
+ *
+ * @param neededWriteMemBytes
+ * writable memory needed in bytes
+ */
+ public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+ mNeededWriteMemBytes = neededWriteMemBytes;
+ }
+
+ /**
+ * set executable memory needed
+ *
+ * @param neededExecMemBytes
+ * executable memory needed in bytes
+ */
+ public void setNeededExecMemBytes(int neededExecMemBytes) {
+ mNeededExecMemBytes = neededExecMemBytes;
+ }
+
+ /**
+ * set the sensors needed for this app
+ *
+ * @param neededSensors
+ * needed Sensors
+ */
+ public void setNeededSensors(int[] neededSensors) {
+ mNeededSensors = neededSensors;
+ }
+
+ public void setOutputEvents(int[] outputEvents) {
+ mOutputEvents = outputEvents;
+ }
+
+ /**
+ * set output events returned by the nano app
+ *
+ * @param appBinary generated events
+ */
+ public void setAppBinary(byte[] appBinary) {
+ mAppBinary = appBinary;
+ }
+
+
+ /**
+ * get the publisher name
+ *
+ * @return publisher name
+ */
+ public String getPublisher() {
+ return mPublisher;
+ }
+
+ /**
+ * get the name of the app
+ *
+ * @return app name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * get the identifier of the app
+ *
+ * @return identifier for this app
+ */
+ public int getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * get the app version
+ *
+ * @return app version
+ */
+ public int getAppVersion() {
+ return mAppVersion;
+ }
+
+ /**
+ * get the ammount of readable memory needed by this app
+ *
+ * @return readable memory needed in bytes
+ */
+ public int getNeededReadMemBytes() {
+ return mNeededReadMemBytes;
+ }
+
+ /**
+ * get the ammount og writable memory needed in bytes
+ *
+ * @return writable memory needed in bytes
+ */
+ public int getNeededWriteMemBytes() {
+ return mNeededWriteMemBytes;
+ }
+
+ /**
+ * executable memory needed in bytes
+ *
+ * @return executable memory needed in bytes
+ */
+ public int getNeededExecMemBytes() {
+ return mNeededExecMemBytes;
+ }
+
+ /**
+ * get the sensors needed by this app
+ *
+ * @return sensors needed
+ */
+ public int[] getNeededSensors() {
+ return mNeededSensors;
+ }
+
+ /**
+ * get the events generated by this app
+ *
+ * @return generated events
+ */
+ public int[] getOutputEvents() {
+ return mOutputEvents;
+ }
+
+ /**
+ * get the binary for this app
+ *
+ * @return app binary
+ */
+ public byte[] getAppBinary() {
+ return mAppBinary;
+ }
+
+ private NanoApp(Parcel in) {
+ mPublisher = in.readString();
+ mName = in.readString();
+
+ mAppId = in.readInt();
+ mAppVersion = in.readInt();
+ mNeededReadMemBytes = in.readInt();
+ mNeededWriteMemBytes = in.readInt();
+ mNeededExecMemBytes = in.readInt();
+
+ int mNeededSensorsLength = in.readInt();
+ mNeededSensors = new int[mNeededSensorsLength];
+ in.readIntArray(mNeededSensors);
+
+ int mOutputEventsLength = in.readInt();
+ mOutputEvents = new int[mOutputEventsLength];
+ in.readIntArray(mOutputEvents);
+
+ int binaryLength = in.readInt();
+ mAppBinary = new byte[binaryLength];
+ in.readByteArray(mAppBinary);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPublisher);
+ out.writeString(mName);
+ out.writeInt(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mNeededReadMemBytes);
+ out.writeInt(mNeededWriteMemBytes);
+ out.writeInt(mNeededExecMemBytes);
+
+ out.writeInt(mNeededSensors.length);
+ out.writeIntArray(mNeededSensors);
+
+ out.writeInt(mOutputEvents.length);
+ out.writeIntArray(mOutputEvents);
+
+ out.writeInt(mAppBinary.length);
+ out.writeByteArray(mAppBinary);
+ }
+
+ public static final Parcelable.Creator<NanoApp> CREATOR
+ = new Parcelable.Creator<NanoApp>() {
+ public NanoApp createFromParcel(Parcel in) {
+ return new NanoApp(in);
+ }
+
+ public NanoApp[] newArray(int size) {
+ return new NanoApp[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.aidl b/core/java/android/hardware/location/NanoAppFilter.aidl
new file mode 100644
index 0000000..cc6d475
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.location;
+/*
+@hide
+*/
+parcelable NanoAppFilter;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
new file mode 100644
index 0000000..ac341e4
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppFilter {
+
+ // The appId, can be set to APP_ID_ANY
+ private long mAppId;
+
+ // Version to filter apps
+ private int mAppVersion;
+
+ // filtering spec for version
+ private int mVersionRestrictionMask;
+
+ // If APP_ID is any, then a match is performef with the vendor mask
+ private long mAppIdVendorMask;
+
+ // Id of the context hub this instance is expected on
+ private int mContextHubId;
+
+ /**
+ * Flag indicating any version. With this flag set, all versions shall match provided version.
+ */
+ public static final int FLAGS_VERSION_ANY = -1;
+ /**
+ * If this flag is set, only versions strictly greater than the version specified shall match.
+ */
+ public static final int FLAGS_VERSION_GREAT_THAN = 2;
+ /**
+ * If this flag is set, only versions strictly less than the version specified shall match.
+ */
+ public static final int FLAGS_VERSION_LESS_THAN = 4;
+ public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
+
+ /**
+ * If this flag is set, only versions strictly equal to the version specified shall match.
+ */
+ public static final int APP_ANY = -1;
+
+ /**
+ * If this flag is set, all vendors shall match.
+ */
+ public static final int VENDOR_ANY = -1;
+
+ /**
+ * If this flag is set, any hub shall match.
+ */
+ public static final int HUB_ANY = -1;
+
+ private NanoAppFilter(Parcel in) {
+ mAppId = in.readLong();
+ mAppVersion = in.readInt();
+ mVersionRestrictionMask = in.readInt();
+ mAppIdVendorMask = in.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+
+ out.writeLong(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mVersionRestrictionMask);
+ out.writeLong(mAppIdVendorMask);
+ }
+
+ /**
+ * Create a filter
+ *
+ * @param appId application id
+ * @param appVersion application version
+ * @param versionMask version
+ * @param vendorMask vendor
+ */
+ public NanoAppFilter(long appId, int appVersion, int versionMask, long vendorMask) {
+ mAppId = appId;
+ mAppVersion = appVersion;
+ mVersionRestrictionMask = versionMask;
+ mAppIdVendorMask = vendorMask;
+ }
+
+ private boolean versionsMatch(int versionRestrictionMask, int expected, int actual){
+ // some refactoring of version restriction mask is needed, until then, return all
+ return true;
+ }
+ /**
+ *
+ * @param nano app instance info
+ *
+ * @return true if this is a match, false otherwise
+ */
+ public boolean testMatch(NanoAppInstanceInfo info) {
+ if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+ (mAppId == APP_ANY || info.getAppId() == mAppId) &&
+ // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
+ (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static final Parcelable.Creator<NanoAppFilter> CREATOR
+ = new Parcelable.Creator<NanoAppFilter>() {
+ public NanoAppFilter createFromParcel(Parcel in) {
+ return new NanoAppFilter(in);
+ }
+
+ public NanoAppFilter[] newArray(int size) {
+ return new NanoAppFilter[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
new file mode 100644
index 0000000..c8c40d7
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.location;
+/*
+@hide
+*/
+parcelable NanoAppInstanceInfo;
\ No newline at end of file
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
new file mode 100644
index 0000000..ac62919
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 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.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppInstanceInfo {
+ private String mPublisher;
+ private String mName;
+
+ private int mAppId;
+ private int mAppVersion;
+
+ private int mNeededReadMemBytes;
+ private int mNeededWriteMemBytes;
+ private int mNeededExecMemBytes;
+
+ private int[] mNeededSensors;
+ private int[] mOutputEvents;
+
+ private int mContexthubId;
+ private int mHandle;
+
+ public NanoAppInstanceInfo() {
+ }
+
+ /**
+ * get the publisher of this app
+ *
+ * @return String - name of the publisher
+ */
+ public String getPublisher() {
+ return mPublisher;
+ }
+
+
+ /**
+ * set the publisher name for the app
+ *
+ * @param publisher - name of the publisher
+ */
+ public void setPublisher(String publisher) {
+ mPublisher = publisher;
+ }
+
+ /**
+ * get the name of the app
+ *
+ * @return String - name of the app
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * set the name of the app
+ *
+ * @param name - name of the app
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * Get the application identifier
+ *
+ * @return int - application identifier
+ */
+ public int getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * Set the application identifier
+ *
+ * @param appId - application identifier
+ */
+ public void setAppId(int appId) {
+ mAppId = appId;
+ }
+
+ /**
+ * Set the application version
+ *
+ * @return int - version of the app
+ */
+ public int getAppVersion() {
+ return mAppVersion;
+ }
+
+ /**
+ * Set the application version
+ *
+ * @param appVersion - version of the app
+ */
+ public void setAppVersion(int appVersion) {
+ mAppVersion = appVersion;
+ }
+
+ /**
+ * Get the read memory needed by the app
+ *
+ * @return int - readable memory needed in bytes
+ */
+ public int getNeededReadMemBytes() {
+ return mNeededReadMemBytes;
+ }
+
+ /**
+ * Set the read memory needed by the app
+ *
+ * @param neededReadMemBytes - readable Memory needed in bytes
+ */
+ public void setNeededReadMemBytes(int neededReadMemBytes) {
+ mNeededReadMemBytes = neededReadMemBytes;
+ }
+
+ /**
+ * get writable memory needed by the app
+ *
+ * @return int - writable memory needed by the app
+ */
+ public int getNeededWriteMemBytes() {
+ return mNeededWriteMemBytes;
+ }
+
+ /**
+ * set writable memory needed by the app
+ *
+ * @param neededWriteMemBytes - writable memory needed by the
+ * app
+ */
+ public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+ mNeededWriteMemBytes = neededWriteMemBytes;
+ }
+
+ /**
+ * get executable memory needed by the app
+ *
+ * @return int - executable memory needed by the app
+ */
+ public int getNeededExecMemBytes() {
+ return mNeededExecMemBytes;
+ }
+
+ /**
+ * set executable memory needed by the app
+ *
+ * @param neededExecMemBytes - executable memory needed by the
+ * app
+ */
+ public void setNeededExecMemBytes(int neededExecMemBytes) {
+ mNeededExecMemBytes = neededExecMemBytes;
+ }
+
+ /**
+ * Get the sensors needed by this app
+ *
+ * @return int[] all the required sensors needed by this app
+ */
+ public int[] getNeededSensors() {
+ return mNeededSensors;
+ }
+
+ /**
+ * set the sensors needed by this app
+ *
+ * @param neededSensors - all the sensors needed by this app
+ */
+ public void setNeededSensors(int[] neededSensors) {
+ mNeededSensors = neededSensors;
+ }
+
+ /**
+ * get the events generated by this app
+ *
+ * @return all the events that can be generated by this app
+ */
+ public int[] getOutputEvents() {
+ return mOutputEvents;
+ }
+
+ /**
+ * set the output events that can be generated by this app
+ *
+ * @param outputEvents - the events that may be generated by
+ * this app
+ */
+ public void setOutputEvents(int[] outputEvents) {
+ mOutputEvents = outputEvents;
+ }
+
+ /**
+ * get the context hub identifier
+ *
+ * @return int - system unique hub identifier
+ */
+ public int getContexthubId() {
+ return mContexthubId;
+ }
+
+ /**
+ * set the context hub identifier
+ *
+ * @param contexthubId - system wide unique identifier
+ */
+ public void setContexthubId(int contexthubId) {
+ mContexthubId = contexthubId;
+ }
+
+ /**
+ * get a handle to the nano app instance
+ *
+ * @return int - handle to this instance
+ */
+ public int getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * set the handle for an app instance
+ *
+ * @param handle - handle to this instance
+ */
+ public void setHandle(int handle) {
+ mHandle = handle;
+ }
+
+
+ private NanoAppInstanceInfo(Parcel in) {
+ mPublisher = in.readString();
+ mName = in.readString();
+
+ mAppId = in.readInt();
+ mAppVersion = in.readInt();
+ mNeededReadMemBytes = in.readInt();
+ mNeededWriteMemBytes = in.readInt();
+ mNeededExecMemBytes = in.readInt();
+
+ int mNeededSensorsLength = in.readInt();
+ mNeededSensors = new int[mNeededSensorsLength];
+ in.readIntArray(mNeededSensors);
+
+ int mOutputEventsLength = in.readInt();
+ mOutputEvents = new int[mOutputEventsLength];
+ in.readIntArray(mOutputEvents);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPublisher);
+ out.writeString(mName);
+ out.writeInt(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mContexthubId);
+ out.writeInt(mNeededReadMemBytes);
+ out.writeInt(mNeededWriteMemBytes);
+ out.writeInt(mNeededExecMemBytes);
+
+ out.writeInt(mNeededSensors.length);
+ out.writeIntArray(mNeededSensors);
+
+ out.writeInt(mOutputEvents.length);
+ out.writeIntArray(mOutputEvents);
+
+ }
+
+ public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
+ = new Parcelable.Creator<NanoAppInstanceInfo>() {
+ public NanoAppInstanceInfo createFromParcel(Parcel in) {
+ return new NanoAppInstanceInfo(in);
+ }
+
+ public NanoAppInstanceInfo[] newArray(int size) {
+ return new NanoAppInstanceInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index bcc1213..344d06e 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -144,6 +144,7 @@
}
/** @hide */
+ @SystemApi
public static UserHandle of(@UserIdInt int userId) {
return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 6321122..1ac798b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1382,7 +1382,7 @@
/**
* Returns information for all users on this device.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @return the list of users that were created.
+ * @return the list of users that exist on the device.
* @hide
*/
public List<UserInfo> getUsers() {
@@ -1395,6 +1395,29 @@
}
/**
+ * Returns serial numbers of all users on this device.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * @param excludeDying specify if the list should exclude users being removed.
+ * @return the list of serial numbers of users that exist on the device.
+ * @hide
+ */
+ @SystemApi
+ public long[] getSerialNumbersOfUsers(boolean excludeDying) {
+ try {
+ List<UserInfo> users = mService.getUsers(excludeDying);
+ long[] result = new long[users.size()];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = users.get(i).serialNumber;
+ }
+ return result;
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get users list", re);
+ return null;
+ }
+ }
+
+ /**
* @return the user's account name, null if not found.
* @hide
*/
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index fda6326..ebb12fd 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.annotation.SystemApi;
import android.annotation.XmlRes;
import android.app.Activity;
import android.content.Context;
@@ -24,8 +25,8 @@
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.Log;
@@ -110,7 +111,13 @@
* managed by this instance.
*/
private int mSharedPreferencesMode;
-
+
+ private static final int STORAGE_DEFAULT = 0;
+ private static final int STORAGE_DEVICE_ENCRYPTED = 1;
+ private static final int STORAGE_CREDENTIAL_ENCRYPTED = 2;
+
+ private int mStorage = STORAGE_DEFAULT;
+
/**
* The {@link PreferenceScreen} at the root of the preference hierarchy.
*/
@@ -343,6 +350,46 @@
}
/**
+ * Sets the storage location used internally by this class to be the default
+ * provided by the hosting {@link Context}.
+ */
+ public void setStorageDefault() {
+ mStorage = STORAGE_DEFAULT;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Explicitly set the storage location used internally by this class to be
+ * device-encrypted storage.
+ * <p>
+ * Data stored in device-encrypted storage is typically encrypted with a key
+ * tied to the physical device, and it can be accessed when the device has
+ * booted successfully, both <em>before and after</em> the user has
+ * authenticated with their credentials (such as a lock pattern or PIN).
+ * Because device-encrypted data is available before user authentication,
+ * you should carefully consider what data you store using this mode.
+ *
+ * @see Context#createDeviceEncryptedStorageContext()
+ */
+ public void setStorageDeviceEncrypted() {
+ mStorage = STORAGE_DEVICE_ENCRYPTED;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Explicitly set the storage location used internally by this class to be
+ * credential-encrypted storage.
+ *
+ * @see Context#createCredentialEncryptedStorageContext()
+ * @hide
+ */
+ @SystemApi
+ public void setStorageCredentialEncrypted() {
+ mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
+ mSharedPreferences = null;
+ }
+
+ /**
* Gets a SharedPreferences instance that preferences managed by this will
* use.
*
@@ -351,7 +398,20 @@
*/
public SharedPreferences getSharedPreferences() {
if (mSharedPreferences == null) {
- mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
+ final Context storageContext;
+ switch (mStorage) {
+ case STORAGE_DEVICE_ENCRYPTED:
+ storageContext = mContext.createDeviceEncryptedStorageContext();
+ break;
+ case STORAGE_CREDENTIAL_ENCRYPTED:
+ storageContext = mContext.createCredentialEncryptedStorageContext();
+ break;
+ default:
+ storageContext = mContext;
+ break;
+ }
+
+ mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
mSharedPreferencesMode);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bc0d7d6..c9c0cde 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -501,6 +501,23 @@
"android.settings.USER_DICTIONARY_SETTINGS";
/**
+ * Activity Action: Show settings to configure the hardware keyboard layout.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ *
+ * @see android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_KEYBOARD_LAYOUT_SETTINGS =
+ "android.settings.KEYBOARD_LAYOUT_SETTINGS";
+
+ /**
* Activity Action: Adds a word to the user dictionary.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 772eeec..0c5a5fc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -589,14 +589,14 @@
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
/**
- * Window type: Windows that are overlaid <em>only</em> by an {@link
+ * Window type: Windows that are overlaid <em>only</em> by a connected {@link
* android.accessibilityservice.AccessibilityService} for interception of
* user interactions without changing the windows an accessibility service
* can introspect. In particular, an accessibility service can introspect
* only windows that a sighted user can interact with which is they can touch
* these windows or can type into these windows. For example, if there
* is a full screen accessibility overlay that is touchable, the windows
- * below it will be introspectable by an accessibility service regardless
+ * below it will be introspectable by an accessibility service even though
* they are covered by a touchable window.
*/
public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1327ea1..b673386 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -38,8 +38,8 @@
/**
* This class represents a node of the window content as well as actions that
* can be requested from its source. From the point of view of an
- * {@link android.accessibilityservice.AccessibilityService} a window content is
- * presented as tree of accessibility node info which may or may not map one-to-one
+ * {@link android.accessibilityservice.AccessibilityService} a window's content is
+ * presented as a tree of accessibility node infos, which may or may not map one-to-one
* to the view hierarchy. In other words, a custom view is free to report itself as
* a tree of accessibility node info.
* </p>
@@ -50,7 +50,7 @@
* <p>
* Please refer to {@link android.accessibilityservice.AccessibilityService} for
* details about how to obtain a handle to window content as a tree of accessibility
- * node info as well as familiarizing with the security model.
+ * node info as well as details about the security model.
* </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
@@ -2422,18 +2422,30 @@
}
/**
- * Gets the text selection start.
+ * Gets the text selection start or the cursor position.
+ * <p>
+ * If no text is selected, both this method and
+ * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
+ * the current location of the cursor.
+ * </p>
*
- * @return The text selection start if there is selection or -1.
+ * @return The text selection start, the cursor location if there is no selection, or -1 if
+ * there is no text selection and no cursor.
*/
public int getTextSelectionStart() {
return mTextSelectionStart;
}
/**
- * Gets the text selection end.
+ * Gets the text selection end if text is selected.
+ * <p>
+ * If no text is selected, both this method and
+ * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
+ * the current location of the cursor.
+ * </p>
*
- * @return The text selection end if there is selection or -1.
+ * @return The text selection end, the cursor location if there is no selection, or -1 if
+ * there is no text selection and no cursor.
*/
public int getTextSelectionEnd() {
return mTextSelectionEnd;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 4d4acb9..1cf15ac 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -201,7 +201,6 @@
needsFill = true;
} else if (mFillColor != SK_ColorTRANSPARENT) {
mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
- outCanvas->drawPath(renderPath, mPaint);
needsFill = true;
}
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 025133f..3b892cb 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -150,4 +150,8 @@
mJavaObjStatus = UNKNOWN_ERROR;
}
+uint32_t JMediaDataSource::getFlags() {
+ return 0;
+}
+
} // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 2bc237e..34624eb 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -45,6 +45,7 @@
virtual ssize_t readAt(off64_t offset, size_t size);
virtual status_t getSize(off64_t* size);
virtual void close();
+ virtual uint32_t getFlags();
private:
// Protect all member variables with mLock because this object will be
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index ad567d3..210682f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.graphics.Color;
@@ -227,6 +228,26 @@
}
/**
+ * Check if an application is suspended.
+ *
+ * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+ * or {@code null} if the application is not suspended.
+ */
+ public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
+ int userId) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ try {
+ ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
+ if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
+ return getProfileOrDeviceOwnerOnCallingUser(context);
+ }
+ } catch (RemoteException e) {
+ // Nothing to do
+ }
+ return null;
+ }
+
+ /**
* Check if account management for a specific type of account is disabled by admin.
* Only a profile or device owner can disable account management. So, we check if account
* management is disabled and return profile or device owner on the calling user.
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index e4d0fec..88313bb 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -12,6 +12,7 @@
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
+ android-support-v17-leanback \
framework-protos
LOCAL_JAVA_LIBRARIES := telephony-common
@@ -30,10 +31,12 @@
frameworks/support/v7/preference/res \
frameworks/support/v14/preference/res \
frameworks/support/v7/appcompat/res \
- frameworks/support/v7/recyclerview/res
+ frameworks/support/v7/recyclerview/res \
+ frameworks/support/v17/leanback/res
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat
+ --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat \
+ --extra-packages android.support.v17.leanback
ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 21abb90..2713fb5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -236,6 +236,20 @@
</intent-filter>
</activity>
+ <activity android:name=".recents.tv.RecentsTvActivity"
+ android:label="@string/accessibility_desc_recent_apps"
+ android:exported="false"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
+ android:stateNotNeeded="true"
+ android:resumeWhilePausing="true"
+ android:screenOrientation="behind"
+ android:theme="@style/RecentsTheme.Wallpaper">
+ <intent-filter>
+ <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+ </intent-filter>
+ </activity>
+
<!-- Callback for dismissing screenshot notification after a share target is picked -->
<receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
android:process=":screenshot"
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
new file mode 100644
index 0000000..b4543bd
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<com.android.systemui.recents.tv.views.RecentsTvView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false" >
+
+ <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
+ android:id="@+id/task_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:descendantFocusability="beforeDescendants"
+ android:gravity="center"
+ android:paddingStart="@dimen/recents_tv_grid_row_padding"
+ android:paddingEnd="@dimen/recents_tv_grid_row_padding"
+ android:focusable="true"/>
+
+</com.android.systemui.recents.tv.views.RecentsTvView>
+
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_task_card_view.xml
new file mode 100644
index 0000000..fa1daad
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_card_view.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:layout_gravity="center"
+ android:layout_centerInParent="true">
+
+ <RelativeLayout
+ android:layout_width="@dimen/recents_tv_card_width"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_gravity="center">
+ <ImageView
+ android:id="@+id/card_view_thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/recents_tv_card_height"
+ android:scaleType="centerCrop"
+ android:gravity="center"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"/>
+
+ <RelativeLayout
+ android:id="@+id/card_info_field"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/card_view_thumbnail"
+ android:background="@color/recents_tv_card_background_color" >
+ <TextView
+ android:id="@+id/card_title_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="false"
+ android:includeFontPadding="true"
+ android:minLines="1"
+ android:maxLines="2"
+ android:textColor="@color/recents_tv_card_title_text_color"
+ android:ellipsize="end" />
+ <TextView
+ android:id="@+id/card_content_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/card_title_text"
+ android:includeFontPadding="true"
+ android:minLines="1"
+ android:maxLines="2"
+ android:textColor="@color/recents_tv_card_content_text_color"
+ android:ellipsize="end" />
+ <ImageView
+ android:id="@+id/card_extra_badge"
+ android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+ android:scaleType="fitCenter"
+ android:background="@android:color/transparent"
+ android:contentDescription="@null"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"/>
+ </RelativeLayout>
+ </RelativeLayout>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 955efb5..19bc755 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -28,9 +28,6 @@
<declare-styleable name="NotificationLinearLayout">
<attr name="insetLeft" format="dimension" />
</declare-styleable>
- <declare-styleable name="NotificationRowLayout">
- <attr name="rowHeight" format="dimension" />
- </declare-styleable>
<declare-styleable name="RecentsPanelView">
<attr name="recentItemLayout" format="reference" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
new file mode 100644
index 0000000..6f4c983
--- /dev/null
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2016, 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.
+ */
+-->
+<resources>
+ <color name="recents_tv_card_background_color">#FF37474F</color>
+ <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
+ <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
+ <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8b0350a..32d09e8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -606,5 +606,4 @@
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
-
</resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
new file mode 100644
index 0000000..77605bd
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2016, 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.
+ */
+-->
+<resources>
+ <!-- Dimens for recents card in the recents view on tv -->
+ <dimen name="recents_tv_card_width">150dip</dimen>
+ <dimen name="recents_tv_card_height">85dip</dimen>
+ <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+
+ <!-- Padding for grid view in recents view on tv -->
+ <dimen name="recents_tv_grid_row_padding">56dip</dimen>
+ <dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
+ <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
+ <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+
+ <!-- Values for focus animation -->
+ <dimen name="recents_tv_unselected_item_z">6dp</dimen>
+ <dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
new file mode 100644
index 0000000..bfd8f8b
--- /dev/null
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<resources>
+ <integer name="item_scale_anim_duration">150</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
new file mode 100644
index 0000000..45cdc07
--- /dev/null
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <item format="float" type="raw" name="unselected_scale">1.0</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 27d4c0e..c7e5ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -35,6 +35,10 @@
public class HumanInteractionClassifier extends Classifier {
private static final String HIC_ENABLE = "HIC_enable";
private static final float FINGER_DISTANCE = 0.1f;
+
+ /** Default value for the HIC_ENABLE setting: 1 - enabled, 0 - disabled */
+ private static final int HIC_ENABLE_DEFAULT = 1;
+
private static HumanInteractionClassifier sInstance = null;
private final Handler mHandler = new Handler();
@@ -101,9 +105,9 @@
}
private void updateConfiguration() {
- mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
+ mEnableClassifier = 0 != Settings.Global.getInt(
mContext.getContentResolver(),
- HIC_ENABLE, 0);
+ HIC_ENABLE, HIC_ENABLE_DEFAULT);
}
public void setType(int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 789e72e..35000d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -23,7 +24,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -271,7 +271,7 @@
protected void checkIfRestrictionEnforced(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
- userRestriction, UserHandle.myUserId());
+ userRestriction, ActivityManager.getCurrentUser());
if (admin != null) {
state.disabledByPolicy = true;
state.enforcedAdmin = admin;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 6a07a07..dbb7423f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,10 @@
@Override
protected void handleClick() {
+ if (!mController.canConfigBluetooth()) {
+ mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+ return;
+ }
if (!mState.value) {
mState.value = true;
mController.setBluetoothEnabled(true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index db86047..2f37943 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -66,6 +68,8 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
+ state.disabledByPolicy = mController.isTetheringAllowed();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
if (arg instanceof Boolean) {
state.value = (boolean) arg;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 724659c6..8328897 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -85,6 +87,8 @@
// bug is fixed, this should be reverted to only hiding it on secure lock screens:
// state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
state.value = locationEnabled;
+ state.disabledByPolicy = mController.isUserLocationRestricted();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
if (locationEnabled) {
state.icon = mEnable;
state.label = mContext.getString(R.string.quick_settings_location_label);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b78fd22..d1301cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,10 +19,12 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
+import android.app.UiModeManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -87,7 +89,10 @@
public final static String RECENTS_PACKAGE = "com.android.systemui";
public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
+ public final static String RECENTS_TV_ACTIVITY = "com.android.systemui.recents.tv.RecentsTvActivity";
+ //Used to store tv or non-tv activty for use in creating intents.
+ private final String mRecentsIntentActivityName;
/**
* An implementation of ITaskStackListener, that allows us to listen for changes to the system
* task stacks and update recents accordingly.
@@ -210,6 +215,14 @@
launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
launchOpts.onlyLoadForCache = true;
loader.loadTasks(mContext, plan, launchOpts);
+
+ //Manager used to determine if we are running on tv or not
+ UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
+ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
+ mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
+ } else {
+ mRecentsIntentActivityName = RECENTS_ACTIVITY;
+ }
}
public void onBootCompleted() {
@@ -906,10 +919,11 @@
launchState.launchedViaDragGesture = mDraggingInRecents;
Intent intent = new Intent();
- intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
+ intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 2882cec..aa006d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -81,6 +81,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
/**
@@ -266,8 +267,9 @@
ComponentName topActivity = topTask.topActivity;
// Check if the front most activity is recents
- if (topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
- topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)) {
+ if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
+ (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
+ topActivity.getClassName().equals(RecentsImpl.RECENTS_TV_ACTIVITY)))) {
if (isHomeTopMost != null) {
isHomeTopMost.value = false;
}
@@ -356,6 +358,13 @@
}
/**
+ * Returns whether the given stack id is the pinned stack id.
+ */
+ public static boolean isPinnedStack(int stackId){
+ return stackId == PINNED_STACK_ID;
+ }
+
+ /**
* Returns whether the given stack id is the docked stack id.
*/
public static boolean isDockedStack(int stackId) {
@@ -968,4 +977,20 @@
public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
mWm.requestAppKeyboardShortcuts(receiver);
}
+
+ public void focusPinnedStack() {
+ try {
+ mIam.setFocusedStack(PINNED_STACK_ID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void focusHomeStack() {
+ try {
+ mIam.setFocusedStack(HOME_STACK_ID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
new file mode 100644
index 0000000..6593169
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowManager;
+import com.android.systemui.R;
+import com.android.systemui.recents.*;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.RecentsTvView;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.tv.pip.PipManager;
+
+import java.util.ArrayList;
+/**
+ * The main TV recents activity started by the RecentsImpl.
+ */
+public class RecentsTvActivity extends Activity implements OnPreDrawListener {
+ private final static String TAG = "RecentsTvActivity";
+ private final static boolean DEBUG = false;
+
+ public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
+
+ private boolean mFinishedOnStartup;
+ private RecentsPackageMonitor mPackageMonitor;
+ private long mLastTabKeyEventTime;
+ private boolean mIgnoreAltTabRelease;
+
+ private RecentsTvView mRecentsView;
+ private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
+ private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+
+
+ /**
+ * A common Runnable to finish Recents by launching Home with an animation depending on the
+ * last activity launch state. Generally we always launch home when we exit Recents rather than
+ * just finishing the activity since we don't know what is behind Recents in the task stack.
+ */
+ class FinishRecentsRunnable implements Runnable {
+ Intent mLaunchIntent;
+
+ /**
+ * Creates a finish runnable that starts the specified intent.
+ */
+ public FinishRecentsRunnable(Intent launchIntent) {
+ mLaunchIntent = launchIntent;
+ }
+
+ @Override
+ public void run() {
+ try {
+ RecentsActivityLaunchState launchState =
+ Recents.getConfiguration().getLaunchState();
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsTvActivity.this,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_enter :
+ R.anim.recents_to_launcher_enter,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_exit :
+ R.anim.recents_to_launcher_exit);
+ startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+ } catch (Exception e) {
+ Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
+ }
+ }
+ }
+
+ private void updateRecentsTasks() {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
+ if (plan == null) {
+ plan = loader.createLoadPlan(this);
+ }
+
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ if (!plan.hasTasks()) {
+ loader.preloadTasks(plan, -1, launchState.launchedFromHome);
+ }
+ TaskStack stack = plan.getTaskStack();
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.runningTaskId = launchState.launchedToTaskId;
+ loadOpts.numVisibleTasks = stack.getStackTaskCount();
+ loadOpts.numVisibleTaskThumbnails = stack.getStackTaskCount();
+ loader.loadTasks(this, plan, loadOpts);
+
+
+ mRecentsView.setTaskStack(stack);
+ if (mTaskStackViewAdapter == null) {
+ mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+ mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
+ } else {
+ mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+ }
+
+ if (launchState.launchedToTaskId != -1) {
+ ArrayList<Task> tasks = stack.getStackTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task t = tasks.get(i);
+ if (t.key.id == launchState.launchedToTaskId) {
+ t.isLaunchTarget = true;
+ break;
+ }
+ }
+ }
+ }
+
+ boolean dismissRecentsToLaunchTargetTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // If we have a focused Task, launch that Task now
+ if (mRecentsView.launchPreviousTask()) return true;
+ // If none of the other cases apply, then just go Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ }
+ return false;
+ }
+
+ boolean dismissRecentsToFocusedTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // If we have a focused Task, launch that Task now
+ if (mRecentsView.launchFocusedTask()) return true;
+ // If none of the other cases apply, then just go Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ return true;
+ }
+ return false;
+ }
+
+ void dismissRecentsToHome(boolean animateTaskViews) {
+ DismissRecentsToHomeAnimationStarted dismissEvent =
+ new DismissRecentsToHomeAnimationStarted(animateTaskViews);
+ dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+ dismissEvent.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ }
+ });
+ EventBus.getDefault().send(dismissEvent);
+ }
+
+ boolean dismissRecentsToHomeIfVisible(boolean animated) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // Return to Home
+ dismissRecentsToHome(animated);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mFinishedOnStartup = false;
+
+ // In the case that the activity starts up before the Recents component has initialized
+ // (usually when debugging/pushing the SysUI apk), just finish this activity.
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp == null) {
+ mFinishedOnStartup = true;
+ finish();
+ return;
+ }
+
+ // Register this activity with the event bus
+ EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
+ mPackageMonitor = new RecentsPackageMonitor();
+ mPackageMonitor.register(this);
+
+ // Set the Recents layout
+ setContentView(R.layout.recents_on_tv);
+
+ mRecentsView = (RecentsTvView) findViewById(R.id.recents_view);
+ mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+
+ // Create the home intent runnable
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ // Update the recent tasks
+ updateRecentsTasks();
+
+ // If this is a new instance from a configuration change, then we have to manually trigger
+ // the enter animation state, or if recents was relaunched by AM, without going through
+ // the normal mechanisms
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+ !launchState.launchedFromAppWithThumbnail;
+ if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ // Notify that recents is now visible
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+ }
+
+ @Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ mIgnoreAltTabRelease = false;
+ // Notify that recents is now hidden
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+
+ // Workaround for b/22542869, if the RecentsActivity is started again, but without going
+ // through SystemUI, we need to reset the config launch flags to ensure that we do not
+ // wait on the system to send a signal that was never queued.
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ launchState.launchedFromHome = false;
+ launchState.launchedFromSearchHome = false;
+ launchState.launchedFromAppWithThumbnail = false;
+ launchState.launchedToTaskId = -1;
+ launchState.launchedWithAltTab = false;
+ launchState.launchedHasConfigurationChanged = false;
+ launchState.launchedViaDragGesture = false;
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ // In the case that the activity finished on startup, just skip the unregistration below
+ if (mFinishedOnStartup) {
+ return;
+ }
+
+ // Unregister any broadcast receivers for the task loader
+ mPackageMonitor.unregister();
+
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ if (loader != null) {
+ loader.onTrimMemory(level);
+ }
+ }
+
+ @Override
+ public void onMultiWindowModeChanged(boolean multiWindowMode) {
+ super.onMultiWindowModeChanged(multiWindowMode);
+ if (!multiWindowMode) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.loadIcons = false;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1, false);
+ loader.loadTasks(this, loadPlan, launchOpts);
+ EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP: {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ PipManager.getInstance().showPipMenu();
+ ssp.focusPinnedStack();
+ return true;
+ }
+ case KeyEvent.KEYCODE_DPAD_DOWN: {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ PipManager.getInstance().showPipOverlay(false);
+ ssp.focusHomeStack();
+ return true;
+ }
+ case KeyEvent.KEYCODE_DEL:
+ case KeyEvent.KEYCODE_FORWARD_DEL: {
+ EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+ return true;
+ }
+ default:
+ break;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public void onUserInteraction() {
+ EventBus.getDefault().send(new UserInteractionEvent());
+ }
+
+ @Override
+ public void onBackPressed() {
+ // Back behaves like the recents button so just trigger a toggle event
+ EventBus.getDefault().send(new ToggleRecentsEvent());
+ }
+
+ /**** EventBus events ****/
+
+ public final void onBusEvent(ToggleRecentsEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ if (launchState.launchedFromHome) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
+ }
+
+ public final void onBusEvent(HideRecentsEvent event) {
+ if (event.triggeredFromAltTab) {
+ // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
+ if (!mIgnoreAltTabRelease) {
+ dismissRecentsToFocusedTaskOrHome();
+ }
+ } else if (event.triggeredFromHomeKey) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ // Do nothing
+ }
+ }
+
+ public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+ EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+ mRecentsView.invalidate();
+ }
+
+ public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ int launchToTaskId = launchState.launchedToTaskId;
+ if (launchToTaskId != -1 &&
+ (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.cancelWindowTransition(launchState.launchedToTaskId);
+ ssp.cancelThumbnailTransition(getTaskId());
+ }
+ }
+
+ public final void onBusEvent(DeleteTaskDataEvent event) {
+ // Remove any stored data from the loader
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ loader.deleteTaskData(event.task, false);
+
+ // Remove the task from activity manager
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.removeTask(event.task.key.id);
+ }
+
+ public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.hasDockedTask()) {
+ mRecentsView.showEmptyView();
+ } else {
+ // Just go straight home (no animation necessary because there are no more task views)
+ dismissRecentsToHome(false /* animateTaskViews */);
+ }
+ }
+
+ public final void onBusEvent(LaunchTaskFailedEvent event) {
+ // Return to Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+ // We post to make sure that this information is delivered after this traversals is
+ // finished.
+ mRecentsView.post(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().endProlongedAnimations();
+ }
+ });
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
new file mode 100644
index 0000000..8212c73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+import com.android.systemui.R;
+
+public class ViewFocusAnimator implements View.OnFocusChangeListener {
+ private final float mUnselectedScale;
+ private final float mSelectedScaleDelta;
+ private final float mUnselectedZ;
+ private final float mSelectedZDelta;
+ private final int mAnimDuration;
+ private final Interpolator mFocusInterpolator;
+
+ protected View mTargetView;
+ private float mFocusProgress;
+
+ ObjectAnimator mFocusAnimation;
+
+ public ViewFocusAnimator(View view) {
+ mTargetView = view;
+ final Resources res = view.getResources();
+
+ mTargetView.setOnFocusChangeListener(this);
+
+ TypedValue out = new TypedValue();
+ res.getValue(R.raw.unselected_scale, out, true);
+ mUnselectedScale = out.getFloat();
+ mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
+ mUnselectedScale;
+
+ mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
+ mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
+
+ mAnimDuration = res.getInteger(R.integer.item_scale_anim_duration);
+
+ mFocusInterpolator = new AccelerateDecelerateInterpolator();
+
+ mFocusAnimation = ObjectAnimator.ofFloat(this, "focusProgress", 0.0f);
+ mFocusAnimation.setDuration(mAnimDuration);
+ mFocusAnimation.setInterpolator(mFocusInterpolator);
+
+ setFocusProgress(0.0f);
+
+ mFocusAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTargetView.setHasTransientState(true);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTargetView.setHasTransientState(false);
+ }
+ });
+ }
+
+ public void setFocusProgress(float level) {
+ mFocusProgress = level;
+
+ float scale = mUnselectedScale + (level * mSelectedScaleDelta);
+ float z = mUnselectedZ + (level * mSelectedZDelta);
+
+ mTargetView.setScaleX(scale);
+ mTargetView.setScaleY(scale);
+ mTargetView.setZ(z);
+ }
+
+ public float getFocusProgress() {
+ return mFocusProgress;
+ }
+
+ public void animateFocus(boolean focused) {
+ if (mFocusAnimation.isStarted()) {
+ mFocusAnimation.cancel();
+ }
+
+ float target = focused ? 1.0f : 0.0f;
+
+ if (getFocusProgress() != target) {
+ mFocusAnimation.setFloatValues(getFocusProgress(), target);
+ mFocusAnimation.start();
+ }
+ }
+
+ public void setFocusImmediate(boolean focused) {
+ if (mFocusAnimation.isStarted()) {
+ mFocusAnimation.cancel();
+ }
+
+ float target = focused ? 1.0f : 0.0f;
+
+ setFocusProgress(target);
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v != mTargetView) {
+ return;
+ }
+ changeSize(hasFocus);
+ }
+
+ protected void changeSize(boolean hasFocus) {
+ ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
+ int width = lp.width;
+ int height = lp.height;
+
+ if (width < 0 && height < 0) {
+ mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ height = mTargetView.getMeasuredHeight();
+ }
+
+ if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
+ mTargetView.getVisibility() == View.VISIBLE) {
+ animateFocus(hasFocus);
+ } else {
+ setFocusImmediate(hasFocus);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
new file mode 100644
index 0000000..c4d5b2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
+/**
+ * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView.
+ */
+public class RecentsTvView extends FrameLayout {
+
+ private static final String TAG = "RecentsTvView";
+ private static final boolean DEBUG = false;
+
+ private TaskStack mStack;
+ private TaskStackHorizontalGridView mTaskStackHorizontalView;
+ private View mEmptyView;
+ private boolean mAwaitingFirstLayout = true;
+ private Rect mSystemInsets = new Rect();
+
+
+ public RecentsTvView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ setWillNotDraw(false);
+
+ LayoutInflater inflater = LayoutInflater.from(context);
+ mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+ addView(mEmptyView);
+ }
+
+ public void setTaskStack(TaskStack stack) {
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ mStack = stack;
+
+ if (mTaskStackHorizontalView != null) {
+ mTaskStackHorizontalView.reset();
+ mTaskStackHorizontalView.setStack(stack);
+ } else {
+ mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
+ mTaskStackHorizontalView.setStack(stack);
+ }
+
+
+ if (stack.getStackTaskCount() > 0) {
+ hideEmptyView();
+ } else {
+ showEmptyView();
+ }
+
+ requestLayout();
+ }
+
+ public Task getNextTaskOrTopTask(Task taskToSearch) {
+ Task returnTask = null;
+ boolean found = false;
+ if (mTaskStackHorizontalView != null) {
+ TaskStack stack = mTaskStackHorizontalView.getStack();
+ ArrayList<Task> taskList = stack.getStackTasks();
+ // Iterate the stack views and try and find the focused task
+ for (int j = taskList.size() - 1; j >= 0; --j) {
+ Task task = taskList.get(j);
+ // Return the next task in the line.
+ if (found)
+ return task;
+ // Remember the first possible task as the top task.
+ if (returnTask == null)
+ returnTask = task;
+ if (task == taskToSearch)
+ found = true;
+ }
+ }
+ return returnTask;
+ }
+
+ public boolean launchFocusedTask() {
+ if (mTaskStackHorizontalView != null) {
+ Task task = mTaskStackHorizontalView.getFocusedTask();
+ if (task != null) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Launches the task that recents was launched from if possible */
+ public boolean launchPreviousTask() {
+ if (mTaskStackHorizontalView != null) {
+ TaskStack stack = mTaskStackHorizontalView.getStack();
+ Task task = stack.getLaunchTarget();
+ if (task != null) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Launches a given task. */
+ public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
+ if (mTaskStackHorizontalView != null) {
+ // Iterate the stack views and try and find the given task.
+ List<TaskCardView> taskViews = mTaskStackHorizontalView.getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int j = 0; j < taskViewCount; j++) {
+ TaskCardView tv = taskViews.get(j);
+ if (tv.getTask() == task) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Hides the task stack and shows the empty view.
+ */
+ public void showEmptyView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mEmptyView.bringToFront();
+ }
+
+ /**
+ * Shows the task stack and hides the empty view.
+ */
+ public void hideEmptyView() {
+ mEmptyView.setVisibility(View.INVISIBLE);
+ }
+
+ /**
+ * Returns the last known system insets.
+ */
+ public Rect getSystemInsets() {
+ return mSystemInsets;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+
+ /**
+ * This is called with the full size of the window since we are handling our own insets.
+ */
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mTaskStackHorizontalView != null && mTaskStackHorizontalView.getVisibility() != GONE) {
+ mTaskStackHorizontalView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
+ }
+
+ // Layout the empty view
+ mEmptyView.layout(left, top, right, bottom);
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mSystemInsets.set(insets.getSystemWindowInsets());
+ requestLayout();
+ return insets;
+ }
+
+ /**** EventBus Events ****/
+
+ public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+ // If we are going home, cancel the previous task's window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+ }
+
+ public final void onBusEvent(TaskStackUpdatedEvent event) {
+ mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+ mStack.createAffiliatedGroupings(getContext());
+ }
+
+
+ public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+ if (!event.visible) {
+ // Reset the view state
+ mAwaitingFirstLayout = true;
+ }
+ }
+
+
+ public void setTaskStackViewAdapter(TaskStackHorizontalViewAdapter taskStackViewAdapter) {
+ if(mTaskStackHorizontalView != null) {
+ mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
new file mode 100644
index 0000000..b36a228
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+import com.android.systemui.recents.model.Task;
+
+public class TaskCardView extends RelativeLayout {
+
+ private ImageView mThumbnailView;
+ private TextView mTitleTextView;
+ private TextView mContentTextView;
+ private ImageView mBadgeView;
+ private Task mTask;
+
+ private ViewFocusAnimator mViewFocusAnimator;
+
+ public TaskCardView(Context context) {
+ this(context, null);
+ }
+
+ public TaskCardView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mViewFocusAnimator = new ViewFocusAnimator(this);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+ mTitleTextView = (TextView) findViewById(R.id.card_title_text);
+ mContentTextView = (TextView) findViewById(R.id.card_content_text);
+ mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
+ }
+
+ public void init(Task task) {
+ mTask = task;
+ mThumbnailView.setImageBitmap(task.thumbnail);
+ mTitleTextView.setText(task.title);
+ mContentTextView.setText(task.contentDescription);
+ mBadgeView.setImageDrawable(task.icon);
+ }
+
+ public Task getTask() {
+ return mTask;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
new file mode 100644
index 0000000..b505d65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv.views;
+
+
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.util.AttributeSet;
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
+import com.android.systemui.recents.views.TaskViewAnimation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Horizontal Grid View Implementation to show the Task Stack for TV.
+ */
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+
+ private TaskStack mStack;
+ private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
+ private Task mFocusedTask;
+
+
+ public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ setItemMargin((int) getResources().getDimension(R.dimen.recents_tv_gird_card_spacing));
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+ /**
+ * Resets this view for reuse.
+ */
+ public void reset() {
+ // Reset the focused task
+ resetFocusedTask(getFocusedTask());
+ requestLayout();
+ }
+
+ /**
+ * @param task - Task to reset
+ */
+ private void resetFocusedTask(Task task) {
+ if (task != null) {
+ TaskCardView tv = getChildViewForTask(task);
+ if (tv != null) {
+ tv.requestFocus();
+ }
+ }
+ mFocusedTask = null;
+ }
+
+ /**
+ * Sets the task stack.
+ * @param stack
+ */
+ public void setStack(TaskStack stack) {
+ //Set new stack
+ mStack = stack;
+ if (mStack != null) {
+ mStack.setCallbacks(this);
+ }
+ //Layout with new stack
+ requestLayout();
+ }
+
+ /**
+ * @return Returns the task stack.
+ */
+ public TaskStack getStack() {
+ return mStack;
+ }
+
+ /**
+ * @return - The focused task.
+ */
+ public Task getFocusedTask() {
+ return mFocusedTask;
+ }
+
+ /**
+ * @param task
+ * @return Child view for given task
+ */
+ public TaskCardView getChildViewForTask(Task task) {
+ List<TaskCardView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskCardView tv = taskViews.get(i);
+ if (tv.getTask() == task) {
+ return tv;
+ }
+ }
+ return null;
+ }
+
+ public List<TaskCardView> getTaskViews() {
+ return mTaskViews;
+ }
+
+ @Override
+ public void onStackTaskAdded(TaskStack stack, Task newTask){
+ getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
+ }
+
+ @Override
+ public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
+ Task newFrontMostTask, TaskViewAnimation animation) {
+ getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
+ if (mFocusedTask == removedTask) {
+ resetFocusedTask(removedTask);
+ }
+ // If there are no remaining tasks, then just close recents
+ if (mStack.getStackTaskCount() == 0) {
+ boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
+ if (shouldFinishActivity) {
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+ }
+ }
+ }
+
+ @Override
+ public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation) {
+ //No history task on tv
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
new file mode 100644
index 0000000..0ee7b49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.tv.views;
+
+import android.app.Activity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+import android.support.v7.widget.RecyclerView;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskStackHorizontalViewAdapter extends
+ RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
+
+ private static final String TAG = "TaskStackHorizontalViewAdapter";
+ private List<Task> mTaskList;
+
+ static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
+ private TaskCardView mTaskCardView;
+ private Task mTask;
+ public ViewHolder(View v) {
+ super(v);
+ if(v instanceof TaskCardView) {
+ mTaskCardView = (TaskCardView) v;
+ }
+ }
+
+ public void init(Task task) {
+ mTaskCardView.init(task);
+ mTask = task;
+ mTaskCardView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ try {
+ ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+ ((Activity)(v.getContext())).finish();
+ } catch (Exception e) {
+ Log.e(TAG, v.getContext()
+ .getString(R.string.recents_launch_error_message, mTask.title), e);
+ }
+
+ }
+ }
+
+ public TaskStackHorizontalViewAdapter(List tasks) {
+ mTaskList = new ArrayList<>(tasks);
+ }
+
+ public void setNewStackTasks(List tasks) {
+ mTaskList.clear();
+ mTaskList.addAll(tasks);
+ notifyDataSetChanged();
+ }
+ @Override
+ public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.recents_task_card_view, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.init(mTaskList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mTaskList.size();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 635e66d..3da8098 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -460,16 +460,16 @@
if (mDark == dark || mContractedChild == null) return;
mDark = dark;
dark = dark && !mShowingLegacyBackground;
- if (mVisibleType == VISIBLE_TYPE_CONTRACTED) {
+ if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
mContractedWrapper.setDark(dark, fade, delay);
}
- if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
+ if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
mExpandedWrapper.setDark(dark, fade, delay);
}
- if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
+ if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
mHeadsUpWrapper.setDark(dark, fade, delay);
}
- if (mSingleLineView != null && mVisibleType == VISIBLE_TYPE_SINGLELINE) {
+ if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
mSingleLineView.setDark(dark, fade, delay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index bed64a3..eb30120 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -30,6 +30,7 @@
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -62,8 +63,8 @@
private SimpleArrayMap<String, Integer> mFacetPackageMap
= new SimpleArrayMap<String, Integer>();
- private List<Intent> mIntents = new ArrayList<Intent>();
- private List<Intent> mLongPressIntents = new ArrayList<Intent>();
+ private List<Intent> mIntents;
+ private List<Intent> mLongPressIntents;
private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
@@ -112,16 +113,19 @@
throw new RuntimeException("car_facet array lengths do not match");
}
+ mIntents = createEmptyIntentList(icons.length());
+ mLongPressIntents = createEmptyIntentList(icons.length());
+
for (int i = 0; i < icons.length(); i++) {
Drawable icon = icons.getDrawable(i);
try {
- mIntents.add(i,
+ mIntents.set(i,
Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME));
String longpressUri = longpressIntents.getString(i);
boolean hasLongpress = !longpressUri.isEmpty();
if (hasLongpress) {
- mLongPressIntents.add(i,
+ mLongPressIntents.set(i,
Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME));
}
@@ -299,4 +303,8 @@
setCurrentFacet(index);
startActivity(mLongPressIntents.get(index));
}
+
+ private List<Intent> createEmptyIntentList(int size) {
+ return Arrays.asList(new Intent[size]);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 97bf4b4..60c1911 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -35,6 +35,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
+ super.setDark(dark, fade, delay);
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index f43a5d0..85f789c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -95,6 +95,7 @@
@Override
public void notifyContentUpdated(StatusBarNotification notification) {
+ super.notifyContentUpdated(notification);
// Reinspect the notification.
resolveHeaderViews();
updateInvertHelper();
@@ -150,6 +151,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
+ super.setDark(dark, fade, delay);
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 3475d13..9910dee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -172,6 +172,9 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
super.setDark(dark, fade, delay);
setPictureGrayscale(dark, fade, delay);
setProgressBarDark(dark, fade, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index a1cf07e..f50b976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -31,6 +31,7 @@
public abstract class NotificationViewWrapper implements TransformableView {
protected final View mView;
+ protected boolean mDark;
public static NotificationViewWrapper wrap(Context ctx, View v) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -56,13 +57,17 @@
* @param fade whether to animate the transition if the mode changes
* @param delay if fading, the delay of the animation
*/
- public abstract void setDark(boolean dark, boolean fade, long delay);
+ public void setDark(boolean dark, boolean fade, long delay) {
+ mDark = dark;
+ }
/**
* Notifies this wrapper that the content of the view might have changed.
* @param notification
*/
- public void notifyContentUpdated(StatusBarNotification notification) {};
+ public void notifyContentUpdated(StatusBarNotification notification) {
+ mDark = false;
+ };
/**
* Update the appearance of the expand button.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 8fa9c7e..e7e2ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -33,6 +33,7 @@
Collection<CachedBluetoothDevice> getDevices();
void connect(CachedBluetoothDevice device);
void disconnect(CachedBluetoothDevice device);
+ boolean canConfigBluetooth();
public interface Callback {
void onBluetoothStateChange(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index a04edf7..6439bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,11 +16,14 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -39,6 +42,8 @@
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final LocalBluetoothManager mLocalBluetoothManager;
+ private final UserManager mUserManager;
+ private final int mCurrentUser;
private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
@@ -54,6 +59,14 @@
onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
}
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
+ }
+
+ @Override
+ public boolean canConfigBluetooth() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
+ UserHandle.of(mCurrentUser));
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 7ca91a5..b036936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,6 +22,7 @@
boolean isHotspotEnabled();
boolean isHotspotSupported();
void setHotspotEnabled(boolean enabled);
+ boolean isTetheringAllowed();
public interface Callback {
void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 5719f76..61d26c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,12 +16,15 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.TetherUtil;
@@ -39,13 +42,17 @@
private final Receiver mReceiver = new Receiver();
private final ConnectivityManager mConnectivityManager;
private final Context mContext;
+ private final UserManager mUserManager;
+ private final int mCurrentUser;
private int mHotspotState;
public HotspotControllerImpl(Context context) {
mContext = context;
- mConnectivityManager = (ConnectivityManager)context.getSystemService(
+ mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,6 +102,12 @@
return TetherUtil.isTetheringSupported(mContext);
}
+ @Override
+ public boolean isTetheringAllowed() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
+ UserHandle.of(mCurrentUser));
+ }
+
static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..401943e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,6 +21,7 @@
boolean setLocationEnabled(boolean enabled);
void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
+ boolean isUserLocationRestricted();
/**
* A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 7517f97..436a40d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,6 +52,7 @@
private AppOpsManager mAppOpsManager;
private StatusBarManager mStatusBarManager;
+ private final int mCurrentUser;
private boolean mAreActiveLocationRequests;
@@ -73,6 +74,7 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mStatusBarManager
= (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -103,10 +105,6 @@
* @return true if attempt to change setting was successful.
*/
public boolean setLocationEnabled(boolean enabled) {
- int currentUserId = ActivityManager.getCurrentUser();
- if (isUserLocationRestricted(currentUserId)) {
- return false;
- }
final ContentResolver cr = mContext.getContentResolver();
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
@@ -115,7 +113,7 @@
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+ .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
}
/**
@@ -133,11 +131,10 @@
/**
* Returns true if the current user is restricted from using location.
*/
- private boolean isUserLocationRestricted(int userId) {
+ public boolean isUserLocationRestricted() {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- return um.hasUserRestriction(
- UserManager.DISALLOW_SHARE_LOCATION,
- new UserHandle(userId));
+ return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+ UserHandle.of(mCurrentUser));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e4ded67..f5869b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -622,7 +622,7 @@
private void checkIfAddUserDisallowed(UserRecord record) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
- UserManager.DISALLOW_ADD_USER, UserHandle.myUserId());
+ UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
if (admin != null) {
record.isDisabledByAdmin = true;
record.enforcedAdmin = admin;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index b7a41e2..964688b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,12 +17,15 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_JACK_FLAGS := --multi-dex native
+
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview
+ --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview \
+ --extra-packages android.support.v17.leanback
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
@@ -35,6 +38,7 @@
frameworks/support/v14/preference/res \
frameworks/support/v7/appcompat/res \
frameworks/support/v7/recyclerview/res \
+ frameworks/support/v17/leanback/res \
frameworks/base/packages/SystemUI/res \
frameworks/base/packages/Keyguard/res
@@ -48,7 +52,8 @@
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference
+ android-support-v14-preference \
+ android-support-v17-leanback
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 76fbebf..b5982c3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12970,6 +12970,9 @@
final StringBuilder sb = new StringBuilder(1024);
appendDropBoxProcessHeaders(process, processName, sb);
+ sb.append("Foreground: ")
+ .append(process.isInterestingToUserLocked() ? "Yes" : "No")
+ .append("\n");
if (activity != null) {
sb.append("Activity: ").append(activity.shortComponentName).append("\n");
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e0880ad..e6fa837 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -74,6 +74,12 @@
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
+ /** Screen content area excluding IM windows, etc. */
+ private final Rect mContentBounds = new Rect();
+
+ /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
+ private final Rect mAdjustedBounds = new Rect();
+
/** Whether mBounds is fullscreen */
private boolean mFullscreen = true;
@@ -164,6 +170,85 @@
return mTmpRect.equals(bounds);
}
+ void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+ if (mFullscreen) {
+ return;
+ }
+ // Update bounds of containing tasks.
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTasks.get(taskNdx);
+ if (task.isTwoFingerScrollMode()) {
+ // If we're scrolling we don't care about your bounds or configs,
+ // they should be null as if we were in fullscreen.
+ task.resizeLocked(null, null, false /* forced */);
+ task.getBounds(mTmpRect2);
+ task.scrollLocked(mTmpRect2);
+ } else if (task.isResizeable()) {
+ task.getBounds(mTmpRect2);
+ mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+ task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
+ }
+ }
+ }
+
+ void adjustForIME(final WindowState imeWin) {
+ final int dockedSide = getDockSide();
+ final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+ final Rect adjustedBounds = mAdjustedBounds;
+ if (imeWin == null || !dockedTopOrBottom) {
+ // If mContentBounds is already empty, it means we're not applying
+ // any adjustments, so nothing to do; otherwise clear any adjustments.
+ if (!mContentBounds.isEmpty()) {
+ mContentBounds.setEmpty();
+ adjustedBounds.set(mBounds);
+ alignTasksToAdjustedBounds(adjustedBounds);
+ }
+ return;
+ }
+
+ final Rect displayContentRect = mTmpRect;
+ final Rect contentBounds = mTmpRect2;
+
+ // Calculate the content bounds excluding the area occupied by IME
+ mDisplayContent.getContentRect(displayContentRect);
+ contentBounds.set(displayContentRect);
+ int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+ imeTop += imeWin.getGivenContentInsetsLw().top;
+ if (contentBounds.bottom > imeTop) {
+ contentBounds.bottom = imeTop;
+ }
+
+ // If content bounds not changing, nothing to do.
+ if (mContentBounds.equals(contentBounds)) {
+ return;
+ }
+
+ // Content bounds changed, need to apply adjustments depending on dock sides.
+ mContentBounds.set(contentBounds);
+ adjustedBounds.set(mBounds);
+ final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+ if (dockedSide == DOCKED_TOP) {
+ // If this stack is docked on top, we make it smaller so the bottom stack is not
+ // occluded by IME. We shift its bottom up by the height of the IME (capped by
+ // the display content rect). Note that we don't change the task bounds.
+ adjustedBounds.bottom = Math.max(
+ adjustedBounds.bottom - yOffset, displayContentRect.top);
+ } else {
+ // If this stack is docked on bottom, we shift it up so that it's not occluded by
+ // IME. We try to move it up by the height of the IME window (although the best
+ // we could do is to make the top stack fully collapsed).
+ final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
+ adjustedBounds.top = Math.max(
+ adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+ adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+
+ // We also move the member tasks together, taking care not to resize them.
+ // Resizing might cause relaunch, and IME window may not come back after that.
+ alignTasksToAdjustedBounds(adjustedBounds);
+ }
+ }
+
private boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
@@ -193,6 +278,16 @@
mBounds.set(bounds);
mRotation = rotation;
+
+ // Clear the adjusted content bounds as they're no longer valid.
+ // If IME is still visible, these will be re-applied.
+ // Note that we don't clear mContentBounds here, so that we know the last IME
+ // adjust we applied.
+ // If user starts dragging the dock divider while IME is visible, the new bounds
+ // we received are based on the actual screen location of the divider. It already
+ // accounted for the IME window, so we don't want to adjust again.
+ mAdjustedBounds.set(mBounds);
+
return true;
}
@@ -217,9 +312,14 @@
public void getBounds(Rect out) {
if (useCurrentBounds()) {
- // No need to adjust the output bounds if fullscreen or the docked stack is visible
+ // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
+ // no need to adjust the output bounds if fullscreen or the docked stack is visible
// since it is already what we want to represent to the rest of the system.
- out.set(mBounds);
+ if (!mContentBounds.isEmpty()) {
+ out.set(mAdjustedBounds);
+ } else {
+ out.set(mBounds);
+ }
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2b88af4..e0e44dc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -161,6 +161,7 @@
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -8075,8 +8076,29 @@
}
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mWindowMap) {
- getDefaultDisplayContentLocked().getDockedDividerController()
- .reevaluateVisibility(false);
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+
+ displayContent.getDockedDividerController().reevaluateVisibility(false);
+
+ final WindowState imeWin = mInputMethodWindow;
+ final TaskStack focusedStack =
+ mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+ if (imeWin != null && focusedStack != null && imeWin.isVisibleNow()
+ && focusedStack.getDockSide() == DOCKED_BOTTOM){
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack.isVisibleLocked()) {
+ stack.adjustForIME(imeWin);
+ }
+ }
+ } else {
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ stack.adjustForIME(null);
+ }
+ }
}
}
break;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 236ae68e..1b0660d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -195,7 +195,7 @@
private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
- protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
+ private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
@@ -1703,8 +1703,8 @@
* Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
* reminders. Clears alarm if no expirations are configured.
*/
- private void setExpirationAlarmCheckLocked(Context context, int userHandle) {
- final long expiration = getPasswordExpirationLocked(null, userHandle, /* parent */ false);
+ private void setExpirationAlarmCheckLocked(Context context, int userHandle, boolean parent) {
+ final long expiration = getPasswordExpirationLocked(null, userHandle, parent);
final long now = System.currentTimeMillis();
final long timeToExpire = expiration - now;
final long alarmTime;
@@ -1726,11 +1726,12 @@
long token = mInjector.binderClearCallingIdentity();
try {
+ int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
- UserHandle.of(userHandle));
+ UserHandle.of(affectedUserHandle));
am.cancel(pi);
if (alarmTime != 0) {
am.set(AlarmManager.RTC, alarmTime, pi);
@@ -2489,7 +2490,6 @@
synchronized (this) {
final long now = System.currentTimeMillis();
- // Return the strictest policy across all participating admins.
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
userHandle, /* parent */ false);
final int N = admins.size();
@@ -2503,7 +2503,7 @@
DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
}
}
- setExpirationAlarmCheckLocked(mContext, userHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
}
}
@@ -2976,8 +2976,7 @@
saveSettingsLocked(userHandle);
// in case this is the first one, set the alarm on the appropriate user.
- int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
- setExpirationAlarmCheckLocked(mContext, affectedUserHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, parent);
}
}
@@ -4324,7 +4323,7 @@
policy.mFailedPasswordAttempts = 0;
saveSettingsLocked(userHandle);
updatePasswordExpirationsLocked(userHandle);
- setExpirationAlarmCheckLocked(mContext, userHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
// Send a broadcast to each profile using this password as its primary unlock.
sendAdminCommandForLockscreenPoliciesLocked(
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b4bca3e..6c2fcd5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -26,7 +26,10 @@
import android.os.UserManager;
import android.test.AndroidTestCase;
+import com.android.internal.util.ArrayUtils;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/** Test {@link UserManager} functionality. */
@@ -196,6 +199,17 @@
assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
}
+ public void testGetSerialNumbersOfUsers() {
+ UserInfo user1 = createUser("User 1", 0);
+ UserInfo user2 = createUser("User 2", 0);
+ long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
+ String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
+ assertTrue(errMsg + user1.serialNumber,
+ ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
+ assertTrue(errMsg + user2.serialNumber,
+ ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
+ }
+
public void testMaxUsers() {
int N = UserManager.getMaxSupportedUsers();
int count = mUserManager.getUsers().size();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 81031da..bfdac7e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -123,6 +123,7 @@
static final int MSG_PAROLE_END_TIMEOUT = 7;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
+ static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
private final Object mLock = new Object();
Handler mHandler;
@@ -145,7 +146,7 @@
private long mLastAppIdleParoledTime;
long mScreenOnTime;
- long mScreenOnSystemTimeSnapshot;
+ long mLastScreenOnEventRealtime;
@GuardedBy("mLock")
private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
@@ -188,6 +189,8 @@
synchronized (mLock) {
cleanUpRemovedUsersLocked();
+ mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
+ mScreenOnTime = readScreenOnTimeLocked();
}
mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -214,10 +217,6 @@
Context.DISPLAY_SERVICE);
mPowerManager = getContext().getSystemService(PowerManager.class);
- mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
- synchronized (mLock) {
- mScreenOnTime = readScreenOnTimeLocked();
- }
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
synchronized (mLock) {
updateDisplayLocked();
@@ -281,6 +280,11 @@
}
@Override
+ public void onStatsReloaded() {
+ postOneTimeCheckIdleStates();
+ }
+
+ @Override
public long getAppIdleRollingWindowDurationMillis() {
return mAppIdleWallclockThresholdMillis * 2;
}
@@ -359,6 +363,14 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
+ /**
+ * We send a different message to check idle states once, otherwise we would end up
+ * scheduling a series of repeating checkIdleStates each time we fired off one.
+ */
+ void postOneTimeCheckIdleStates() {
+ mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ }
+
/** Check all running users' or specified user's apps to see if they enter an idle state. */
void checkIdleStates(int checkUserId) {
if (!mAppIdleEnabled) {
@@ -385,7 +397,7 @@
userId);
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
timeNow);
final int packageCount = packages.size();
@@ -401,8 +413,6 @@
}
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
- mCheckIdleIntervalMillis);
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -443,21 +453,21 @@
if (screenOn == mScreenOn) return;
mScreenOn = screenOn;
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
if (mScreenOn) {
- mScreenOnSystemTimeSnapshot = now;
+ mLastScreenOnEventRealtime = now;
} else {
- mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
+ mScreenOnTime += now - mLastScreenOnEventRealtime;
writeScreenOnTimeLocked(mScreenOnTime);
}
}
- private long getScreenOnTimeLocked(long now) {
+ long getScreenOnTimeLocked() {
+ long screenOnTime = mScreenOnTime;
if (mScreenOn) {
- return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
- } else {
- return mScreenOnTime;
+ screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
}
+ return screenOnTime;
}
private File getScreenOnTimeFile() {
@@ -527,7 +537,7 @@
if (service == null) {
service = new UserUsageStatsService(getContext(), userId,
new File(mUsageStatsDir, Integer.toString(userId)), this);
- service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
+ service.init(currentTimeMillis, getScreenOnTimeLocked());
mUserState.put(userId, service);
}
return service;
@@ -540,25 +550,18 @@
final long actualSystemTime = System.currentTimeMillis();
final long actualRealtime = SystemClock.elapsedRealtime();
final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
- boolean resetBeginIdleTime = false;
- if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+ final long diffSystemTime = actualSystemTime - expectedSystemTime;
+ if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
// The time has changed.
-
- // Check if it's severe enough a change to reset screenOnTime
- if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
- mScreenOnSystemTimeSnapshot = actualSystemTime;
- mScreenOnTime = 0;
- resetBeginIdleTime = true;
- }
+ Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
final UserUsageStatsService service = mUserState.valueAt(i);
- service.onTimeChanged(expectedSystemTime, actualSystemTime, mScreenOnTime,
- resetBeginIdleTime);
+ service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
+ false);
}
mRealTimeSnapshot = actualRealtime;
mSystemTimeSnapshot = actualSystemTime;
- postCheckIdleStates(UserHandle.USER_ALL);
}
return actualSystemTime;
}
@@ -587,7 +590,7 @@
void reportEvent(UsageEvents.Event event, int userId) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
convertToSystemTimeLocked(event);
final UserUsageStatsService service =
@@ -603,7 +606,6 @@
|| event.mEventType == Event.SYSTEM_INTERACTION
|| event.mEventType == Event.USER_INTERACTION)) {
if (previouslyIdle) {
- //Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
@@ -643,7 +645,7 @@
void forceIdleState(String packageName, int userId, boolean idle) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
final UserUsageStatsService service =
@@ -657,7 +659,6 @@
timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
- // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
if (!idle) {
@@ -796,7 +797,7 @@
timeNow = checkAndGetTimeLocked();
}
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
userService, timeNow, screenOnTime);
@@ -865,7 +866,7 @@
synchronized (mLock) {
timeNow = checkAndGetTimeLocked();
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
List<ApplicationInfo> apps;
@@ -987,7 +988,7 @@
*/
void dump(String[] args, PrintWriter pw) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
+ final long screenOnTime = getScreenOnTimeLocked();
IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
ArraySet<String> argSet = new ArraySet<>();
argSet.addAll(Arrays.asList(args));
@@ -1008,7 +1009,11 @@
}
idpw.decreaseIndent();
}
- pw.println("Screen On Timebase:" + mScreenOnTime);
+ pw.print("Screen On Timebase: ");
+ pw.print(screenOnTime);
+ pw.print(" (");
+ TimeUtils.formatDuration(screenOnTime, pw);
+ pw.println(")");
pw.println();
pw.println("Settings:");
@@ -1042,8 +1047,8 @@
pw.println();
pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
pw.println();
- pw.print("mScreenOnSystemTimeSnapshot=");
- TimeUtils.formatDuration(mScreenOnSystemTimeSnapshot, pw);
+ pw.print("mLastScreenOnEventRealtime=");
+ TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
pw.println();
}
}
@@ -1078,6 +1083,14 @@
case MSG_CHECK_IDLE_STATES:
checkIdleStates(msg.arg1);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+ mCheckIdleIntervalMillis);
+ break;
+
+ case MSG_ONE_TIME_CHECK_IDLE_STATES:
+ mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ checkIdleStates(UserHandle.USER_ALL);
break;
case MSG_CHECK_PAROLE_TIMEOUT:
@@ -1138,7 +1151,7 @@
@Override
public void onChange(boolean selfChange) {
updateSettings();
- postCheckIdleStates(UserHandle.USER_ALL);
+ postOneTimeCheckIdleStates();
}
void updateSettings() {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index aa2cf77..f2045d3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -73,6 +73,7 @@
interface StatsUpdatedListener {
void onStatsUpdated();
+ void onStatsReloaded();
long getAppIdleRollingWindowDurationMillis();
}
@@ -523,6 +524,9 @@
mStatsChanged = false;
updateRolloverDeadline();
+
+ // Tell the listener that the stats reloaded, which may have changed idle states.
+ mListener.onStatsReloaded();
}
private void updateRolloverDeadline() {
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index ff3d29f..ec9e462 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -43,7 +43,8 @@
void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings);
void subscribe(int sessionId, in SubscribeData subscribeData,
in SubscribeSettings subscribeSettings);
- void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength);
+ void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength,
+ int messageId);
void stopSession(int sessionId);
void destroySession(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
index 773f83b..50c34d9 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
@@ -32,7 +32,7 @@
void onMatch(int peerId, in byte[] serviceSpecificInfo,
int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength);
- void onMessageSendSuccess();
- void onMessageSendFail(int reason);
+ void onMessageSendSuccess(int messageId);
+ void onMessageSendFail(int messageId, int reason);
void onMessageReceived(int peerId, in byte[] message, int messageLength);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 877f993..cb82268 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -319,13 +319,14 @@
/**
* {@hide}
*/
- public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength) {
+ public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength,
+ int messageId) {
try {
if (VDBG) {
Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
- + ", messageLength=" + messageLength);
+ + ", messageLength=" + messageLength + ", messageId=" + messageId);
}
- mService.sendMessage(sessionId, peerId, message, messageLength);
+ mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
} catch (RemoteException e) {
Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c6b384e..d0a9410 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -103,8 +103,11 @@
* @param message The message to be transmitted.
* @param messageLength The number of bytes from the {@code message} to be
* transmitted.
+ * @param messageId An arbitrary integer used by the caller to identify the
+ * message. The same integer ID will be returned in the callbacks
+ * indicated message send success or failure.
*/
- public void sendMessage(int peerId, byte[] message, int messageLength) {
- mManager.sendMessage(mSessionId, peerId, message, messageLength);
+ public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) {
+ mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId);
}
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index c9d08c7..d5e59f0 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -210,10 +210,10 @@
msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2);
break;
case LISTEN_MESSAGE_SEND_SUCCESS:
- WifiNanSessionListener.this.onMessageSendSuccess();
+ WifiNanSessionListener.this.onMessageSendSuccess(msg.arg1);
break;
case LISTEN_MESSAGE_SEND_FAIL:
- WifiNanSessionListener.this.onMessageSendFail(msg.arg1);
+ WifiNanSessionListener.this.onMessageSendFail(msg.arg1, msg.arg2);
break;
case LISTEN_MESSAGE_RECEIVED:
WifiNanSessionListener.this.onMessageReceived(msg.arg2,
@@ -306,7 +306,7 @@
* {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
* never both.
*/
- public void onMessageSendSuccess() {
+ public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
}
@@ -325,7 +325,7 @@
* @param reason The failure reason using {@code NanSessionListener.FAIL_*}
* codes.
*/
- public void onMessageSendFail(int reason) {
+ public void onMessageSendFail(int messageId, int reason) {
if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested");
}
@@ -401,19 +401,21 @@
}
@Override
- public void onMessageSendSuccess() {
+ public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess");
Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS);
+ msg.arg1 = messageId;
mHandler.sendMessage(msg);
}
@Override
- public void onMessageSendFail(int reason) {
+ public void onMessageSendFail(int messageId, int reason) {
if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL);
- msg.arg1 = reason;
+ msg.arg1 = messageId;
+ msg.arg2 = reason;
mHandler.sendMessage(msg);
}