diff options
39 files changed, 2063 insertions, 143 deletions
diff --git a/api/current.txt b/api/current.txt index e4962d822a4f..36430bb1e42d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3538,6 +3538,7 @@ package android.app { method public deprecated void setTitleColor(int); method public void setVisible(boolean); method public final void setVolumeControlStream(int); + method public void setVrMode(boolean); method public boolean shouldShowRequestPermissionRationale(java.lang.String); method public boolean shouldUpRecreateTask(android.content.Intent); method public boolean showAssist(android.os.Bundle); @@ -8993,6 +8994,7 @@ package android.content.pm { field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8 field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000 field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4 + field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000 field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20 field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100 field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2 @@ -9556,6 +9558,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; + field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode"; field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch"; field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview"; field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi"; @@ -29311,6 +29314,7 @@ package android.provider { field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location"; field public static final int INCOMING_TYPE = 1; // 0x1 field public static final java.lang.String IS_READ = "is_read"; + field public static final java.lang.String LAST_MODIFIED = "last_modified"; field public static final java.lang.String LIMIT_PARAM_KEY = "limit"; field public static final int MISSED_TYPE = 3; // 0x3 field public static final java.lang.String NEW = "new"; @@ -31581,6 +31585,7 @@ package android.provider { public static final class VoicemailContract.Status implements android.provider.BaseColumns { method public static android.net.Uri buildSourceUri(java.lang.String); + method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int); field public static final java.lang.String CONFIGURATION_STATE = "configuration_state"; field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2 field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1 @@ -31597,6 +31602,9 @@ package android.provider { field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0 field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name"; field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id"; + field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied"; + field public static final java.lang.String QUOTA_TOTAL = "quota_total"; + field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff field public static final java.lang.String SETTINGS_URI = "settings_uri"; field public static final java.lang.String SOURCE_PACKAGE = "source_package"; field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri"; @@ -31613,6 +31621,7 @@ package android.provider { field public static final java.lang.String HAS_CONTENT = "has_content"; field public static final java.lang.String IS_READ = "is_read"; field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail"; + field public static final java.lang.String LAST_MODIFIED = "last_modified"; field public static final java.lang.String MIME_TYPE = "mime_type"; field public static final java.lang.String NUMBER = "number"; field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name"; @@ -33252,6 +33261,7 @@ package android.service.notification { method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); method public final void setNotificationsShown(java.lang.String[]); + field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4 field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1 diff --git a/api/system-current.txt b/api/system-current.txt index 586ea06df874..1a1555579e07 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3643,6 +3643,7 @@ package android.app { method public deprecated void setTitleColor(int); method public void setVisible(boolean); method public final void setVolumeControlStream(int); + method public void setVrMode(boolean); method public boolean shouldShowRequestPermissionRationale(java.lang.String); method public boolean shouldUpRecreateTask(android.content.Intent); method public boolean showAssist(android.os.Bundle); @@ -9261,6 +9262,7 @@ package android.content.pm { field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8 field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000 field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4 + field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000 field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20 field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100 field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2 @@ -9872,6 +9874,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; + field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode"; field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch"; field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview"; field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi"; @@ -31321,6 +31324,7 @@ package android.provider { field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location"; field public static final int INCOMING_TYPE = 1; // 0x1 field public static final java.lang.String IS_READ = "is_read"; + field public static final java.lang.String LAST_MODIFIED = "last_modified"; field public static final java.lang.String LIMIT_PARAM_KEY = "limit"; field public static final int MISSED_TYPE = 3; // 0x3 field public static final java.lang.String NEW = "new"; @@ -33724,6 +33728,7 @@ package android.provider { public static final class VoicemailContract.Status implements android.provider.BaseColumns { method public static android.net.Uri buildSourceUri(java.lang.String); + method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int); field public static final java.lang.String CONFIGURATION_STATE = "configuration_state"; field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2 field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1 @@ -33740,6 +33745,9 @@ package android.provider { field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0 field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name"; field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id"; + field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied"; + field public static final java.lang.String QUOTA_TOTAL = "quota_total"; + field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff field public static final java.lang.String SETTINGS_URI = "settings_uri"; field public static final java.lang.String SOURCE_PACKAGE = "source_package"; field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri"; @@ -33756,6 +33764,7 @@ package android.provider { field public static final java.lang.String HAS_CONTENT = "has_content"; field public static final java.lang.String IS_READ = "is_read"; field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail"; + field public static final java.lang.String LAST_MODIFIED = "last_modified"; field public static final java.lang.String MIME_TYPE = "mime_type"; field public static final java.lang.String NUMBER = "number"; field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name"; @@ -35400,6 +35409,7 @@ package android.service.notification { method public final void setNotificationsShown(java.lang.String[]); method public final void setOnNotificationPostedTrim(int); method public void unregisterAsSystemService() throws android.os.RemoteException; + field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4 field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1 diff --git a/api/test-current.txt b/api/test-current.txt index eccd8b006c82..3531e34a2407 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3538,6 +3538,7 @@ package android.app { method public deprecated void setTitleColor(int); method public void setVisible(boolean); method public final void setVolumeControlStream(int); + method public void setVrMode(boolean); method public boolean shouldShowRequestPermissionRationale(java.lang.String); method public boolean shouldUpRecreateTask(android.content.Intent); method public boolean showAssist(android.os.Bundle); @@ -8993,6 +8994,7 @@ package android.content.pm { field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8 field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000 field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4 + field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000 field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20 field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100 field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2 @@ -9556,6 +9558,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; + field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode"; field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch"; field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview"; field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi"; @@ -29313,6 +29316,7 @@ package android.provider { field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location"; field public static final int INCOMING_TYPE = 1; // 0x1 field public static final java.lang.String IS_READ = "is_read"; + field public static final java.lang.String LAST_MODIFIED = "last_modified"; field public static final java.lang.String LIMIT_PARAM_KEY = "limit"; field public static final int MISSED_TYPE = 3; // 0x3 field public static final java.lang.String NEW = "new"; @@ -31583,6 +31587,7 @@ package android.provider { public static final class VoicemailContract.Status implements android.provider.BaseColumns { method public static android.net.Uri buildSourceUri(java.lang.String); + method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int); field public static final java.lang.String CONFIGURATION_STATE = "configuration_state"; field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2 field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1 @@ -31599,6 +31604,9 @@ package android.provider { field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0 field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name"; field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id"; + field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied"; + field public static final java.lang.String QUOTA_TOTAL = "quota_total"; + field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff field public static final java.lang.String SETTINGS_URI = "settings_uri"; field public static final java.lang.String SOURCE_PACKAGE = "source_package"; field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri"; @@ -31615,6 +31623,7 @@ package android.provider { field public static final java.lang.String HAS_CONTENT = "has_content"; field public static final java.lang.String IS_READ = "is_read"; field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail"; + field public static final java.lang.String LAST_MODIFIED = "last_modified"; field public static final java.lang.String MIME_TYPE = "mime_type"; field public static final java.lang.String NUMBER = "number"; field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name"; @@ -33254,6 +33263,7 @@ package android.service.notification { method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); method public final void setNotificationsShown(java.lang.String[]); + field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4 field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 61fd952d8f73..6d72059e0a47 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6038,6 +6038,22 @@ public class Activity extends ContextThemeWrapper } /** + * Enable or disable virtual reality (VR) mode. + * + * <p>VR mode is a hint to Android system services to switch to modes optimized for + * high-performance stereoscopic rendering.</p> + * + * @param enabled {@code true} to enable this mode. + */ + public void setVrMode(boolean enabled) { + try { + ActivityManagerNative.getDefault().setVrMode(mToken, enabled); + } catch (RemoteException e) { + // pass + } + } + + /** * Start an action mode of the default type {@link ActionMode#TYPE_PRIMARY}. * * @param callback Callback that will manage lifecycle events for this action mode diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index d724823843d7..1b0827331903 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2766,6 +2766,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + case SET_VR_MODE_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final IBinder token = data.readStrongBinder(); + final boolean enable = data.readInt() == 1; + setVrMode(token, enable); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -5896,6 +5904,18 @@ class ActivityManagerProxy implements IActivityManager return res; } + public void setVrMode(IBinder token, boolean enabled) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + data.writeInt(enabled ? 1 : 0); + mRemote.transact(SET_VR_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + @Override public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index f91a0bef7833..0ecf2231665a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -552,6 +552,8 @@ public interface IActivityManager extends IInterface { public void enterPictureInPictureMode(IBinder token) throws RemoteException; + public void setVrMode(IBinder token, boolean enabled) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -917,4 +919,5 @@ public interface IActivityManager extends IInterface { int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353; int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354; int ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355; + int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356; } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index bce5bf37f0eb..abe9822e972f 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -55,6 +55,7 @@ interface INotificationManager void setTopicImportance(String pkg, int uid, in Notification.Topic topic, int importance); int getTopicImportance(String pkg, int uid, in Notification.Topic topic); void setAppImportance(String pkg, int uid, int importance); + boolean doesAppUseTopics(String pkg, int uid); // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 0cb0e9fce251..326735ec4f36 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -276,6 +276,12 @@ public class ActivityInfo extends ComponentInfo */ public static final int FLAG_RESUME_WHILE_PAUSING = 0x4000; /** + * Bit in {@link #flags} indicating that this activity should be run with VR mode enabled. + * + * {@see android.app.Activity#setVrMode(boolean)}. + */ + public static final int FLAG_ENABLE_VR_MODE = 0x8000; + /** * @hide Bit in {@link #flags}: If set, this component will only be seen * by the system user. Only works with broadcast receivers. Set from the * android.R.attr#systemUserOnly attribute. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 40bcc7ed9cde..3235bcff1eaf 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1830,6 +1830,16 @@ public abstract class PackageManager { public static final String FEATURE_MIDI = "android.software.midi"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device implements a an optimized mode for virtual reality (VR) applications that handles + * stereoscopic rendering of notifications, and may potentially also include optimizations to + * reduce latency in the graphics, display, and sensor stacks. Presence of this feature + * also indicates that the VrCore library is included on this device. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_VR_MODE = "android.software.vr.mode"; + + /** * Action to external storage service to clean out removed apps. * @hide */ diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 1d4d57278a57..6a5d857c4a37 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -421,6 +421,13 @@ public class CallLog { public static final String ADD_FOR_ALL_USERS = "add_for_all_users"; /** + * The date the row is last inserted, updated, or marked as deleted, in milliseconds + * since the epoch. Read only. + * <P>Type: INTEGER (long)</P> + */ + public static final String LAST_MODIFIED = "last_modified"; + + /** * If a successful call is made that is longer than this duration, update the phone number * in the ContactsProvider with the normalized version of the number, based on the user's * current country code. diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index 76eaea9998cd..24683cb1d9fd 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -245,6 +245,13 @@ public class VoicemailContract { public static final String DELETED = "deleted"; /** + * The date the row is last inserted, updated, or marked as deleted, in milliseconds + * since the epoch. Read only. + * <P>Type: INTEGER (long)</P> + */ + public static final String LAST_MODIFIED = "last_modified"; + + /** * A convenience method to build voicemail URI specific to a source package by appending * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI. */ @@ -449,6 +456,26 @@ public class VoicemailContract { public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; /** + * Amount of resource that is used by existing voicemail in the visual voicemail inbox, + * or {@link #QUOTA_UNAVAILABLE}. Unit is not specified. + * <P>Type: INTEGER</P> + */ + public static final String QUOTA_OCCUPIED = "quota_occupied"; + + /** + * Total resource in the visual voicemail inbox that can be used, or + * {@link #QUOTA_UNAVAILABLE}. Unit is not specified. + * <P>Type: INTEGER</P> + */ + public static final String QUOTA_TOTAL = "quota_total"; + + /** + * Value for {@link #QUOTA_OCCUPIED} and {@link #QUOTA_TOTAL} to indicate that no + * information is available. + */ + public static final int QUOTA_UNAVAILABLE = -1; + + /** * A convenience method to build status URI specific to a source package by appending * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI. */ @@ -488,6 +515,39 @@ public class VoicemailContract { } /** + * A helper method to set the quota of a voicemail source. Unit is unspecified. + * + * @param context The context from the package calling the method. This will be the source. + * @param accountHandle The handle for the account the source is associated with. + * @param occupied See {@link Status#QUOTA_OCCUPIED} + * @param total See {@link Status#QUOTA_TOTAL} + */ + public static void setQuota(Context context, PhoneAccountHandle accountHandle, int occupied, + int total) { + if (occupied == QUOTA_UNAVAILABLE && total == QUOTA_UNAVAILABLE) { + return; + } + ContentValues values = new ContentValues(); + values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME, + accountHandle.getComponentName().flattenToString()); + values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId()); + if (occupied != QUOTA_UNAVAILABLE) { + values.put(Status.QUOTA_OCCUPIED,occupied); + } + if (total != QUOTA_UNAVAILABLE) { + values.put(Status.QUOTA_TOTAL,total); + } + + ContentResolver contentResolver = context.getContentResolver(); + Uri statusUri = buildSourceUri(context.getPackageName()); + if (isStatusPresent(contentResolver, statusUri)) { + contentResolver.update(statusUri, values, null, null); + } else { + contentResolver.insert(statusUri, values); + } + } + + /** * Determines if a voicemail source exists in the status table. * * @param contentResolver A content resolver constructed from the appropriate context. diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 232d4fe4e979..1e62edc6634f 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -60,6 +60,16 @@ import java.util.List; * <action android:name="android.service.notification.NotificationListenerService" /> * </intent-filter> * </service></pre> + * <p> Typically, while enabled in user settings, this service will be bound on boot or when a + * settings change occurs that could affect whether this service should run. However, for some + * system usage modes, the you may instead specify that this service is instead bound and unbound + * in response to mode changes by including a category in the intent filter. Currently + * supported categories are: + * <ul> + * <li>{@link #CATEGORY_VR_NOTIFICATIONS} - this service is bound when an Activity has enabled + * VR mode. {@see android.app.Activity#setVrMode(boolean)}.</li> + * </ul> + * </p> */ public abstract class NotificationListenerService extends Service { // TAG = "NotificationListenerService[MySubclass]" @@ -162,6 +172,17 @@ public abstract class NotificationListenerService extends Service { = "android.service.notification.NotificationListenerService"; /** + * If this category is declared in the application manifest for a service of this type, this + * service will be bound when VR mode is enabled, and unbound when VR mode is disabled rather + * than the normal lifecycle for a notification service. + * + * {@see android.app.Activity#setVrMode(boolean)} + */ + @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_VR_NOTIFICATIONS = + "android.intent.category.vr.notifications"; + + /** * Implement this method to learn about new notifications as they are posted by apps. * * @param sbn A data structure encapsulating the original {@link android.app.Notification} diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index fe4193224950..544444dfd59f 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -18,9 +18,11 @@ package android.util; import com.android.internal.os.RuntimeInit; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.LineBreakBufferedWriter; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.Writer; import java.net.UnknownHostException; /** @@ -126,7 +128,7 @@ public final class Log { * @param tr An exception to log */ public static int v(String tag, String msg, Throwable tr) { - return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr)); + return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr); } /** @@ -147,7 +149,7 @@ public final class Log { * @param tr An exception to log */ public static int d(String tag, String msg, Throwable tr) { - return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr)); + return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr); } /** @@ -168,7 +170,7 @@ public final class Log { * @param tr An exception to log */ public static int i(String tag, String msg, Throwable tr) { - return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr)); + return printlns(LOG_ID_MAIN, INFO, tag, msg, tr); } /** @@ -189,7 +191,7 @@ public final class Log { * @param tr An exception to log */ public static int w(String tag, String msg, Throwable tr) { - return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr)); + return printlns(LOG_ID_MAIN, WARN, tag, msg, tr); } /** @@ -219,7 +221,7 @@ public final class Log { * @param tr An exception to log */ public static int w(String tag, Throwable tr) { - return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); + return printlns(LOG_ID_MAIN, WARN, tag, "", tr); } /** @@ -240,7 +242,7 @@ public final class Log { * @param tr An exception to log */ public static int e(String tag, String msg, Throwable tr) { - return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr)); + return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr); } /** @@ -292,8 +294,7 @@ public final class Log { // Only mark this as ERROR, do not use ASSERT since that should be // reserved for cases where the system is guaranteed to abort. // The onTerribleFailure call does not always cause a crash. - int bytes = println_native(logId, ERROR, tag, msg + '\n' - + getStackTraceString(localStack ? what : tr)); + int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr); sWtfHandler.onTerribleFailure(tag, what, system); return bytes; } @@ -365,4 +366,107 @@ public final class Log { /** @hide */ public static native int println_native(int bufID, int priority, String tag, String msg); + + /** + * Return the maximum payload the log daemon accepts without truncation. + * @return LOGGER_ENTRY_MAX_PAYLOAD. + */ + private static native int logger_entry_max_payload_native(); + + /** + * Helper function for long messages. Uses the LineBreakBufferedWriter to break + * up long messages and stacktraces along newlines, but tries to write in large + * chunks. This is to avoid truncation. + */ + private static int printlns(int bufID, int priority, String tag, String msg, + Throwable tr) { + ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag); + // Acceptable buffer size. Get the native buffer size, subtract two zero terminators, + // and the length of the tag. + // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It + // is too expensive to compute that ahead of time. + int bufferSize = NoPreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD // Base. + - 2 // Two terminators. + - (tag != null ? tag.length() : 0) // Tag length. + - 32; // Some slack. + // At least assume you can print *some* characters (tag is not too large). + bufferSize = Math.max(bufferSize, 100); + + LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize); + + lbbw.println(msg); + + if (tr != null) { + // This is to reduce the amount of log spew that apps do in the non-error + // condition of the network being unavailable. + Throwable t = tr; + while (t != null) { + if (t instanceof UnknownHostException) { + break; + } + t = t.getCause(); + } + if (t == null) { + tr.printStackTrace(lbbw); + } + } + + lbbw.flush(); + + return logWriter.getWritten(); + } + + /** + * NoPreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid + * a JNI call during logging. + */ + static class NoPreloadHolder { + public final static int LOGGER_ENTRY_MAX_PAYLOAD = + logger_entry_max_payload_native(); + } + + /** + * Helper class to write to the logcat. Different from LogWriter, this writes + * the whole given buffer and does not break along newlines. + */ + private static class ImmediateLogWriter extends Writer { + + private int bufID; + private int priority; + private String tag; + + private int written = 0; + + /** + * Create a writer that immediately writes to the log, using the given + * parameters. + */ + public ImmediateLogWriter(int bufID, int priority, String tag) { + this.bufID = bufID; + this.priority = priority; + this.tag = tag; + } + + public int getWritten() { + return written; + } + + @Override + public void write(char[] cbuf, int off, int len) { + // Note: using String here has a bit of overhead as a Java object is created, + // but using the char[] directly is not easier, as it needs to be translated + // to a C char[] for logging. + written += println_native(bufID, priority, tag, new String(cbuf, off, len)); + } + + @Override + public void flush() { + // Ignored. + } + + @Override + public void close() { + // Ignored. + } + } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index faf26405c199..0ed007dd9b8a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -197,6 +197,10 @@ public final class ViewRootImpl implements ViewParent, // so the window should no longer be active. boolean mStopped = false; + // Set to true if the owner of this window is in ambient mode, + // which means it won't receive input events. + boolean mIsAmbientMode = false; + // Set to true to stop input during an Activity Transition. boolean mPausedForTransition = false; @@ -1032,6 +1036,10 @@ public final class ViewRootImpl implements ViewParent, } } + public void setIsAmbientMode(boolean ambient) { + mIsAmbientMode = ambient; + } + void setWindowStopped(boolean stopped) { if (mStopped != stopped) { mStopped = stopped; @@ -3685,7 +3693,7 @@ public final class ViewRootImpl implements ViewParent, return true; } else if ((!mAttachInfo.mHasWindowFocus && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped - || (mPausedForTransition && !isBack(q.mEvent))) { + || mIsAmbientMode || (mPausedForTransition && !isBack(q.mEvent))) { // This is a focus event and the window doesn't currently have input focus or // has stopped. This could be an event that came back from the previous stage // but the window has lost focus or stopped in the meantime. @@ -5511,6 +5519,8 @@ public final class ViewRootImpl implements ViewParent, writer.println(mProcessInputEventsScheduled); writer.print(innerPrefix); writer.print("mTraversalScheduled="); writer.print(mTraversalScheduled); + writer.print(innerPrefix); writer.print("mIsAmbientMode="); + writer.print(mIsAmbientMode); if (mTraversalScheduled) { writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")"); } else { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 2e884ccc7b25..251f4c802ce6 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1183,6 +1183,13 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH = 0x00008000; /** + * Flag to indicate that this child window should always be laid-out in the parent + * frame regardless of the current windowing mode configuration. + * @hide + */ + public static final int PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME = 0x00010000; + + /** * Control flags that are private to the platform. * @hide */ diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index f4c343a9509a..19e290b71a97 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -16,6 +16,7 @@ package android.widget; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; import com.android.internal.R; @@ -1313,7 +1314,8 @@ public class PopupWindow { p.width = mLastWidth = mWidth; } - p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; + p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH + | PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; // Used for debugging. p.setTitle("PopupWindow:" + Integer.toHexString(hashCode())); diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java new file mode 100644 index 000000000000..3b8f865bec5d --- /dev/null +++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import com.android.internal.R; + +import android.app.ListFragment; +import android.content.Context; +import android.content.res.Resources; +import android.os.Bundle; +import android.util.ArrayMap; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +class LocaleAdapter extends ArrayAdapter<LocalePicker.LocaleInfo> { + final private Map<String, LocalePicker.LocaleInfo> mLevelOne = new ArrayMap<>(); + final private Map<String, HashSet<LocalePicker.LocaleInfo>> mLevelTwo = new ArrayMap<>(); + final private LayoutInflater mInflater; + + final static class LocaleAwareComparator implements Comparator<LocalePicker.LocaleInfo> { + private final Collator mCollator; + + public LocaleAwareComparator(Locale sortLocale) { + mCollator = Collator.getInstance(sortLocale); + } + + @Override + public int compare(LocalePicker.LocaleInfo lhs, LocalePicker.LocaleInfo rhs) { + return mCollator.compare(lhs.getLabel(), rhs.getLabel()); + } + } + + static List<Locale> getCuratedLocaleList(Context context) { + final Resources resources = context.getResources(); + final String[] supportedLocaleCodes = resources.getStringArray(R.array.supported_locales); + + final ArrayList<Locale> result = new ArrayList<>(supportedLocaleCodes.length); + for (String localeId : supportedLocaleCodes) { + Locale locale = Locale.forLanguageTag(localeId); + if (!locale.getCountry().isEmpty()) { + result.add(Locale.forLanguageTag(localeId)); + } + } + return result; + } + + public LocaleAdapter(Context context) { + this(context, getCuratedLocaleList(context)); + } + + static Locale getBaseLocale(Locale locale) { + return new Locale.Builder() + .setLocale(locale) + .setRegion("") + .build(); + } + + // There is no good API available for this, not even in ICU. + // We can revisit this if we get some ICU support later + // + // There are currently several tickets requesting this feature: + // * ICU needs to provide an easy way to titlecase only one first letter + // http://bugs.icu-project.org/trac/ticket/11729 + // * Add "initial case" + // http://bugs.icu-project.org/trac/ticket/8394 + // * Add code for initialCase, toTitlecase don't modify after Lt, + // avoid 49Ers, low-level language-specific casing + // http://bugs.icu-project.org/trac/ticket/10410 + // * BreakIterator.getFirstInstance: Often you need to titlecase just the first + // word, and leave the rest of the string alone. (closed as duplicate) + // http://bugs.icu-project.org/trac/ticket/8946 + // + // A (clunky) option with the current ICU API is: + // BreakIterator breakIterator = BreakIterator.getSentenceInstance(locale); + // String result = UCharacter.toTitleCase(locale, + // source, breakIterator, UCharacter.TITLECASE_NO_LOWERCASE); + // That also means creating BreakIteratos for each locale. Expensive... + private static String toTitleCase(String s, Locale locale) { + if (s.length() == 0) { + return s; + } + final int firstCodePointLen = s.offsetByCodePoints(0, 1); + return s.substring(0, firstCodePointLen).toUpperCase(locale) + + s.substring(firstCodePointLen); + } + + public LocaleAdapter(Context context, List<Locale> locales) { + super(context, R.layout.locale_picker_item, R.id.locale); + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + for (Locale locale : locales) { + Locale baseLocale = getBaseLocale(locale); + String language = baseLocale.toLanguageTag(); + if (!mLevelOne.containsKey(language)) { + String label = toTitleCase(baseLocale.getDisplayName(baseLocale), baseLocale); + mLevelOne.put(language, new LocalePicker.LocaleInfo(label, baseLocale)); + } + + final HashSet<LocalePicker.LocaleInfo> subLocales; + if (mLevelTwo.containsKey(language)) { + subLocales = mLevelTwo.get(language); + } else { + subLocales = new HashSet<>(); + mLevelTwo.put(language, subLocales); + } + String label = locale.getDisplayCountry(locale); + subLocales.add(new LocalePicker.LocaleInfo(label, locale)); + } + + setAdapterLevel(null); + } + + public void setAdapterLevel(String parentLocale) { + this.clear(); + + if (parentLocale == null) { + this.addAll(mLevelOne.values()); + } else { + this.addAll(mLevelTwo.get(parentLocale)); + } + + Locale sortLocale = (parentLocale == null) + ? Locale.getDefault() + : Locale.forLanguageTag(parentLocale); + LocaleAwareComparator comparator = new LocaleAwareComparator(sortLocale); + this.sort(comparator); + + this.notifyDataSetChanged(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view; + TextView text; + if (convertView == null) { + view = mInflater.inflate(R.layout.locale_picker_item, parent, false); + text = (TextView) view.findViewById(R.id.locale); + view.setTag(text); + } else { + view = convertView; + text = (TextView) view.getTag(); + } + LocalePicker.LocaleInfo item = getItem(position); + text.setText(item.getLabel()); + text.setTextLocale(item.getLocale()); + return view; + } +} + +public class LocalePickerWithRegion extends ListFragment { + private static final int LIST_MODE_LANGUAGE = 0; + private static final int LIST_MODE_COUNTRY = 1; + + private LocaleAdapter mAdapter; + private int mDisplayMode = LIST_MODE_LANGUAGE; + + public static interface LocaleSelectionListener { + // You can add any argument if you really need it... + public void onLocaleSelected(Locale locale); + } + + private LocaleSelectionListener mListener = null; + + @Override + public void onActivityCreated(final Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mAdapter = new LocaleAdapter(getContext()); + mAdapter.setAdapterLevel(null); + setListAdapter(mAdapter); + } + + public void setLocaleSelectionListener(LocaleSelectionListener listener) { + mListener = listener; + } + + @Override + public void onResume() { + super.onResume(); + getListView().requestFocus(); + } + + /** + * Each listener needs to call {@link LocalePicker.updateLocale(Locale)} to actually + * change the locale. + * <p/> + * We don't call {@link LocalePicker.updateLocale(Locale)} automatically, as it halts + * the system for a moment and some callers won't want it. + */ + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + final Locale locale = ((LocalePicker.LocaleInfo) getListAdapter().getItem(position)).locale; + // TODO: handle the back buttons to return to the language list + if (mDisplayMode == LIST_MODE_LANGUAGE) { + mDisplayMode = LIST_MODE_COUNTRY; + mAdapter.setAdapterLevel(locale.toLanguageTag()); + return; + } + if (mListener != null) { + mListener.onLocaleSelected(locale); + } + } +} diff --git a/core/java/com/android/internal/util/LineBreakBufferedWriter.java b/core/java/com/android/internal/util/LineBreakBufferedWriter.java new file mode 100644 index 000000000000..f831e7a84d2f --- /dev/null +++ b/core/java/com/android/internal/util/LineBreakBufferedWriter.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import java.io.PrintWriter; +import java.io.Writer; +import java.util.Arrays; + +/** + * A writer that breaks up its output into chunks before writing to its out writer, + * and which is linebreak aware, i.e., chunks will created along line breaks, if + * possible. + * + * Note: this class is not thread-safe. + */ +public class LineBreakBufferedWriter extends PrintWriter { + + /** + * A buffer to collect data until the buffer size is reached. + * + * Note: we manage a char[] ourselves to avoid an allocation when printing to the + * out writer. Otherwise a StringBuilder would have been simpler to use. + */ + private char[] buffer; + + /** + * The index of the first free element in the buffer. + */ + private int bufferIndex; + + /** + * The chunk size (=maximum buffer size) to use for this writer. + */ + private final int bufferSize; + + + /** + * Index of the last newline character discovered in the buffer. The writer will try + * to split there. + */ + private int lastNewline = -1; + + /** + * The line separator for println(). + */ + private final String lineSeparator; + + /** + * Create a new linebreak-aware buffered writer with the given output and buffer + * size. The initial capacity will be a default value. + * @param out The writer to write to. + * @param bufferSize The maximum buffer size. + */ + public LineBreakBufferedWriter(Writer out, int bufferSize) { + this(out, bufferSize, 16); // 16 is the default size of a StringBuilder buffer. + } + + /** + * Create a new linebreak-aware buffered writer with the given output, buffer + * size and initial capacity. + * @param out The writer to write to. + * @param bufferSize The maximum buffer size. + * @param initialCapacity The initial capacity of the internal buffer. + */ + public LineBreakBufferedWriter(Writer out, int bufferSize, int initialCapacity) { + super(out); + this.buffer = new char[Math.min(initialCapacity, bufferSize)]; + this.bufferIndex = 0; + this.bufferSize = bufferSize; + this.lineSeparator = System.getProperty("line.separator"); + } + + /** + * Flush the current buffer. This will ignore line breaks. + */ + @Override + public void flush() { + writeBuffer(bufferIndex); + bufferIndex = 0; + super.flush(); + } + + @Override + public void write(int c) { + if (bufferIndex < bufferSize) { + buffer[bufferIndex] = (char)c; + bufferIndex++; + if ((char)c == '\n') { + lastNewline = bufferIndex; + } + } else { + // This should be an uncommon case, we mostly expect char[] and String. So + // let the chunking be handled by the char[] case. + write(new char[] { (char)c }, 0 ,1); + } + } + + @Override + public void println() { + write(lineSeparator); + } + + @Override + public void write(char[] buf, int off, int len) { + while (bufferIndex + len > bufferSize) { + // Find the next newline in the buffer, see if that's below the limit. + // Repeat. + int nextNewLine = -1; + int maxLength = bufferSize - bufferIndex; + for (int i = 0; i < maxLength; i++) { + if (buf[off + i] == '\n') { + if (bufferIndex + i < bufferSize) { + nextNewLine = i; + } else { + break; + } + } + } + + if (nextNewLine != -1) { + // We can add some more data. + appendToBuffer(buf, off, nextNewLine); + writeBuffer(bufferIndex); + bufferIndex = 0; + lastNewline = -1; + off += nextNewLine + 1; + len -= nextNewLine + 1; + } else if (lastNewline != -1) { + // Use the last newline. + writeBuffer(lastNewline); + removeFromBuffer(lastNewline + 1); + lastNewline = -1; + } else { + // OK, there was no newline, break at a full buffer. + int rest = bufferSize - bufferIndex; + appendToBuffer(buf, off, rest); + writeBuffer(bufferIndex); + bufferIndex = 0; + off += rest; + len -= rest; + } + } + + // Add to the buffer, this will fit. + if (len > 0) { + // Add the chars, find the last newline. + appendToBuffer(buf, off, len); + for (int i = len - 1; i >= 0; i--) { + if (buf[off + i] == '\n') { + lastNewline = bufferIndex - len + i; + break; + } + } + } + } + + @Override + public void write(String s, int off, int len) { + while (bufferIndex + len > bufferSize) { + // Find the next newline in the buffer, see if that's below the limit. + // Repeat. + int nextNewLine = -1; + int maxLength = bufferSize - bufferIndex; + for (int i = 0; i < maxLength; i++) { + if (s.charAt(off + i) == '\n') { + if (bufferIndex + i < bufferSize) { + nextNewLine = i; + } else { + break; + } + } + } + + if (nextNewLine != -1) { + // We can add some more data. + appendToBuffer(s, off, nextNewLine); + writeBuffer(bufferIndex); + bufferIndex = 0; + lastNewline = -1; + off += nextNewLine + 1; + len -= nextNewLine + 1; + } else if (lastNewline != -1) { + // Use the last newline. + writeBuffer(lastNewline); + removeFromBuffer(lastNewline + 1); + lastNewline = -1; + } else { + // OK, there was no newline, break at a full buffer. + int rest = bufferSize - bufferIndex; + appendToBuffer(s, off, rest); + writeBuffer(bufferIndex); + bufferIndex = 0; + off += rest; + len -= rest; + } + } + + // Add to the buffer, this will fit. + if (len > 0) { + // Add the chars, find the last newline. + appendToBuffer(s, off, len); + for (int i = len - 1; i >= 0; i--) { + if (s.charAt(off + i) == '\n') { + lastNewline = bufferIndex - len + i; + break; + } + } + } + } + + /** + * Append the characters to the buffer. This will potentially resize the buffer, + * and move the index along. + * @param buf The char[] containing the data. + * @param off The start index to copy from. + * @param len The number of characters to copy. + */ + private void appendToBuffer(char[] buf, int off, int len) { + if (bufferIndex + len > buffer.length) { + ensureCapacity(bufferIndex + len); + } + System.arraycopy(buf, off, buffer, bufferIndex, len); + bufferIndex += len; + } + + /** + * Append the characters from the given string to the buffer. This will potentially + * resize the buffer, and move the index along. + * @param s The string supplying the characters. + * @param off The start index to copy from. + * @param len The number of characters to copy. + */ + private void appendToBuffer(String s, int off, int len) { + if (bufferIndex + len > buffer.length) { + ensureCapacity(bufferIndex + len); + } + s.getChars(off, off + len, buffer, bufferIndex); + bufferIndex += len; + } + + /** + * Resize the buffer. We use the usual double-the-size plus constant scheme for + * amortized O(1) insert. Note: we expect small buffers, so this won't check for + * overflow. + * @param capacity The size to be ensured. + */ + private void ensureCapacity(int capacity) { + int newSize = buffer.length * 2 + 2; + if (newSize < capacity) { + newSize = capacity; + } + buffer = Arrays.copyOf(buffer, newSize); + } + + /** + * Remove the characters up to (and excluding) index i from the buffer. This will + * not resize the buffer, but will update bufferIndex. + * @param i The number of characters to remove from the front. + */ + private void removeFromBuffer(int i) { + int rest = bufferIndex - i; + if (rest > 0) { + System.arraycopy(buffer, bufferIndex - rest, buffer, 0, rest); + bufferIndex = rest; + } else { + bufferIndex = 0; + } + } + + /** + * Helper method, write the given part of the buffer, [start,length), to the output. + * @param length The number of characters to flush. + */ + private void writeBuffer(int length) { + if (length > 0) { + super.write(buffer, 0, length); + } + } +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a9a198bc40d1..3bde6b3d2f39 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -184,6 +184,8 @@ LOCAL_C_INCLUDES += \ $(call include-path-for, libhardware_legacy)/hardware_legacy \ $(TOP)/frameworks/av/include \ $(TOP)/frameworks/base/media/jni \ + $(TOP)/system/core/base/include \ + $(TOP)/system/core/include \ $(TOP)/system/media/camera/include \ $(TOP)/system/netd/include \ external/pdfium/core/include/fpdfapi \ diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp index 2d23cda5ff15..7719e31f4240 100644 --- a/core/jni/android_util_Log.cpp +++ b/core/jni/android_util_Log.cpp @@ -18,8 +18,10 @@ #define LOG_NAMESPACE "log.tag." #define LOG_TAG "Log_println" +#include <android-base/macros.h> #include <assert.h> #include <cutils/properties.h> +#include <log/logger.h> // For LOGGER_ENTRY_MAX_PAYLOAD. #include <utils/Log.h> #include <utils/String8.h> @@ -109,12 +111,23 @@ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, } /* + * In class android.util.Log: + * private static native int logger_entry_max_payload_native() + */ +static jint android_util_Log_logger_entry_max_payload_native(JNIEnv* env ATTRIBUTE_UNUSED, + jobject clazz ATTRIBUTE_UNUSED) +{ + return static_cast<jint>(LOGGER_ENTRY_MAX_PAYLOAD); +} + +/* * JNI registration. */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable }, { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native }, + { "logger_entry_max_payload_native", "()I", (void*) android_util_Log_logger_entry_max_payload_native }, }; int register_android_util_Log(JNIEnv* env) diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml new file mode 100644 index 000000000000..dae7a2eb3d89 --- /dev/null +++ b/core/res/res/values/locale_config.xml @@ -0,0 +1,507 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/colors.xml +** +** Copyright 2006, 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:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <string-array translatable="false" name="supported_locales"> + <item>af-NA</item> <!-- Afrikaans (Namibia) --> + <item>af-ZA</item> <!-- Afrikaans (South Africa) --> + <item>agq-CM</item> <!-- Aghem (Cameroon) --> + <item>ak-GH</item> <!-- Akan (Ghana) --> + <item>am-ET</item> <!-- Amharic (Ethiopia) --> + <item>ar-AE</item> <!-- Arabic (United Arab Emirates) --> + <item>ar-BH</item> <!-- Arabic (Bahrain) --> + <item>ar-DJ</item> <!-- Arabic (Djibouti) --> + <item>ar-DZ</item> <!-- Arabic (Algeria) --> + <item>ar-EG</item> <!-- Arabic (Egypt) --> + <item>ar-EH</item> <!-- Arabic (Western Sahara) --> + <item>ar-ER</item> <!-- Arabic (Eritrea) --> + <item>ar-IL</item> <!-- Arabic (Israel) --> + <item>ar-IQ</item> <!-- Arabic (Iraq) --> + <item>ar-JO</item> <!-- Arabic (Jordan) --> + <item>ar-KM</item> <!-- Arabic (Comoros) --> + <item>ar-KW</item> <!-- Arabic (Kuwait) --> + <item>ar-LB</item> <!-- Arabic (Lebanon) --> + <item>ar-LY</item> <!-- Arabic (Libya) --> + <item>ar-MA</item> <!-- Arabic (Morocco) --> + <item>ar-MR</item> <!-- Arabic (Mauritania) --> + <item>ar-OM</item> <!-- Arabic (Oman) --> + <item>ar-PS</item> <!-- Arabic (Palestine) --> + <item>ar-QA</item> <!-- Arabic (Qatar) --> + <item>ar-SA</item> <!-- Arabic (Saudi Arabia) --> + <item>ar-SD</item> <!-- Arabic (Sudan) --> + <item>ar-SO</item> <!-- Arabic (Somalia) --> + <item>ar-SS</item> <!-- Arabic (South Sudan) --> + <item>ar-SY</item> <!-- Arabic (Syria) --> + <item>ar-TD</item> <!-- Arabic (Chad) --> + <item>ar-TN</item> <!-- Arabic (Tunisia) --> + <item>ar-YE</item> <!-- Arabic (Yemen) --> + <item>as-IN</item> <!-- Assamese (India) --> + <item>asa-TZ</item> <!-- Asu (Tanzania) --> + <item>az-Cyrl-AZ</item> <!-- Azerbaijani (Cyrillic,Azerbaijan) --> + <item>az-Latn-AZ</item> <!-- Azerbaijani (Latin,Azerbaijan) --> + <item>bas-CM</item> <!-- Basaa (Cameroon) --> + <item>be-BY</item> <!-- Belarusian (Belarus) --> + <item>bem-ZM</item> <!-- Bemba (Zambia) --> + <item>bez-TZ</item> <!-- Bena (Tanzania) --> + <item>bg-BG</item> <!-- Bulgarian (Bulgaria) --> + <item>bm-ML</item> <!-- Bambara (Mali) --> + <item>bn-BD</item> <!-- Bengali (Bangladesh) --> + <item>bn-IN</item> <!-- Bengali (India) --> + <item>bo-CN</item> <!-- Tibetan (China) --> + <item>bo-IN</item> <!-- Tibetan (India) --> + <item>br-FR</item> <!-- Breton (France) --> + <item>brx-IN</item> <!-- Bodo (India) --> + <item>bs-Cyrl-BA</item> <!-- Bosnian (Cyrillic,Bosnia & Herzegovina) --> + <item>bs-Latn-BA</item> <!-- Bosnian (Latin,Bosnia & Herzegovina) --> + <item>ca-AD</item> <!-- Catalan (Andorra) --> + <item>ca-ES</item> <!-- Catalan (Spain) --> + <item>ca-FR</item> <!-- Catalan (France) --> + <item>ca-IT</item> <!-- Catalan (Italy) --> + <item>ce-RU</item> <!-- Chechen (Russia) --> + <item>cgg-UG</item> <!-- Chiga (Uganda) --> + <item>chr-US</item> <!-- Cherokee (United States) --> + <item>cs-CZ</item> <!-- Czech (Czech Republic) --> + <item>cy-GB</item> <!-- Welsh (United Kingdom) --> + <item>da-DK</item> <!-- Danish (Denmark) --> + <item>da-GL</item> <!-- Danish (Greenland) --> + <item>dav-KE</item> <!-- Taita (Kenya) --> + <item>de-AT</item> <!-- German (Austria) --> + <item>de-BE</item> <!-- German (Belgium) --> + <item>de-CH</item> <!-- German (Switzerland) --> + <item>de-DE</item> <!-- German (Germany) --> + <item>de-LI</item> <!-- German (Liechtenstein) --> + <item>de-LU</item> <!-- German (Luxembourg) --> + <item>dje-NE</item> <!-- Zarma (Niger) --> + <item>dsb-DE</item> <!-- Lower Sorbian (Germany) --> + <item>dua-CM</item> <!-- Duala (Cameroon) --> + <item>dyo-SN</item> <!-- Jola-Fonyi (Senegal) --> + <item>dz-BT</item> <!-- Dzongkha (Bhutan) --> + <item>ebu-KE</item> <!-- Embu (Kenya) --> + <item>ee-GH</item> <!-- Ewe (Ghana) --> + <item>ee-TG</item> <!-- Ewe (Togo) --> + <item>el-CY</item> <!-- Greek (Cyprus) --> + <item>el-GR</item> <!-- Greek (Greece) --> + <item>en-AG</item> <!-- English (Antigua & Barbuda) --> + <item>en-AI</item> <!-- English (Anguilla) --> + <item>en-AS</item> <!-- English (American Samoa) --> + <item>en-AT</item> <!-- English (Austria) --> + <item>en-AU</item> <!-- English (Australia) --> + <item>en-BB</item> <!-- English (Barbados) --> + <item>en-BE</item> <!-- English (Belgium) --> + <item>en-BI</item> <!-- English (Burundi) --> + <item>en-BM</item> <!-- English (Bermuda) --> + <item>en-BS</item> <!-- English (Bahamas) --> + <item>en-BW</item> <!-- English (Botswana) --> + <item>en-BZ</item> <!-- English (Belize) --> + <item>en-CA</item> <!-- English (Canada) --> + <item>en-CC</item> <!-- English (Cocos (Keeling) Islands) --> + <item>en-CH</item> <!-- English (Switzerland) --> + <item>en-CK</item> <!-- English (Cook Islands) --> + <item>en-CM</item> <!-- English (Cameroon) --> + <item>en-CX</item> <!-- English (Christmas Island) --> + <item>en-CY</item> <!-- English (Cyprus) --> + <item>en-DE</item> <!-- English (Germany) --> + <item>en-DG</item> <!-- English (Diego Garcia) --> + <item>en-DK</item> <!-- English (Denmark) --> + <item>en-DM</item> <!-- English (Dominica) --> + <item>en-ER</item> <!-- English (Eritrea) --> + <item>en-FI</item> <!-- English (Finland) --> + <item>en-FJ</item> <!-- English (Fiji) --> + <item>en-FK</item> <!-- English (Falkland Islands (Islas Malvinas)) --> + <item>en-FM</item> <!-- English (Micronesia) --> + <item>en-GB</item> <!-- English (United Kingdom) --> + <item>en-GD</item> <!-- English (Grenada) --> + <item>en-GG</item> <!-- English (Guernsey) --> + <item>en-GH</item> <!-- English (Ghana) --> + <item>en-GI</item> <!-- English (Gibraltar) --> + <item>en-GM</item> <!-- English (Gambia) --> + <item>en-GU</item> <!-- English (Guam) --> + <item>en-GY</item> <!-- English (Guyana) --> + <item>en-HK</item> <!-- English (Hong Kong) --> + <item>en-IE</item> <!-- English (Ireland) --> + <item>en-IL</item> <!-- English (Israel) --> + <item>en-IM</item> <!-- English (Isle of Man) --> + <item>en-IN</item> <!-- English (India) --> + <item>en-IO</item> <!-- English (British Indian Ocean Territory) --> + <item>en-JE</item> <!-- English (Jersey) --> + <item>en-JM</item> <!-- English (Jamaica) --> + <item>en-KE</item> <!-- English (Kenya) --> + <item>en-KI</item> <!-- English (Kiribati) --> + <item>en-KN</item> <!-- English (St. Kitts & Nevis) --> + <item>en-KY</item> <!-- English (Cayman Islands) --> + <item>en-LC</item> <!-- English (St. Lucia) --> + <item>en-LR</item> <!-- English (Liberia) --> + <item>en-LS</item> <!-- English (Lesotho) --> + <item>en-MG</item> <!-- English (Madagascar) --> + <item>en-MH</item> <!-- English (Marshall Islands) --> + <item>en-MO</item> <!-- English (Macau) --> + <item>en-MP</item> <!-- English (Northern Mariana Islands) --> + <item>en-MS</item> <!-- English (Montserrat) --> + <item>en-MT</item> <!-- English (Malta) --> + <item>en-MU</item> <!-- English (Mauritius) --> + <item>en-MW</item> <!-- English (Malawi) --> + <item>en-MY</item> <!-- English (Malaysia) --> + <item>en-NA</item> <!-- English (Namibia) --> + <item>en-NF</item> <!-- English (Norfolk Island) --> + <item>en-NG</item> <!-- English (Nigeria) --> + <item>en-NL</item> <!-- English (Netherlands) --> + <item>en-NR</item> <!-- English (Nauru) --> + <item>en-NU</item> <!-- English (Niue) --> + <item>en-NZ</item> <!-- English (New Zealand) --> + <item>en-PG</item> <!-- English (Papua New Guinea) --> + <item>en-PH</item> <!-- English (Philippines) --> + <item>en-PK</item> <!-- English (Pakistan) --> + <item>en-PN</item> <!-- English (Pitcairn Islands) --> + <item>en-PR</item> <!-- English (Puerto Rico) --> + <item>en-PW</item> <!-- English (Palau) --> + <item>en-RW</item> <!-- English (Rwanda) --> + <item>en-SB</item> <!-- English (Solomon Islands) --> + <item>en-SC</item> <!-- English (Seychelles) --> + <item>en-SD</item> <!-- English (Sudan) --> + <item>en-SE</item> <!-- English (Sweden) --> + <item>en-SG</item> <!-- English (Singapore) --> + <item>en-SH</item> <!-- English (St. Helena) --> + <item>en-SI</item> <!-- English (Slovenia) --> + <item>en-SL</item> <!-- English (Sierra Leone) --> + <item>en-SS</item> <!-- English (South Sudan) --> + <item>en-SX</item> <!-- English (Sint Maarten) --> + <item>en-SZ</item> <!-- English (Swaziland) --> + <item>en-TC</item> <!-- English (Turks & Caicos Islands) --> + <item>en-TK</item> <!-- English (Tokelau) --> + <item>en-TO</item> <!-- English (Tonga) --> + <item>en-TT</item> <!-- English (Trinidad & Tobago) --> + <item>en-TV</item> <!-- English (Tuvalu) --> + <item>en-TZ</item> <!-- English (Tanzania) --> + <item>en-UG</item> <!-- English (Uganda) --> + <item>en-UM</item> <!-- English (U.S. Outlying Islands) --> + <item>en-US</item> <!-- English (United States) --> + <item>en-VC</item> <!-- English (St. Vincent & Grenadines) --> + <item>en-VG</item> <!-- English (British Virgin Islands) --> + <item>en-VI</item> <!-- English (U.S. Virgin Islands) --> + <item>en-VU</item> <!-- English (Vanuatu) --> + <item>en-WS</item> <!-- English (Samoa) --> + <item>en-ZA</item> <!-- English (South Africa) --> + <item>en-ZM</item> <!-- English (Zambia) --> + <item>en-ZW</item> <!-- English (Zimbabwe) --> + <item>es-AR</item> <!-- Spanish (Argentina) --> + <item>es-BO</item> <!-- Spanish (Bolivia) --> + <item>es-CL</item> <!-- Spanish (Chile) --> + <item>es-CO</item> <!-- Spanish (Colombia) --> + <item>es-CR</item> <!-- Spanish (Costa Rica) --> + <item>es-CU</item> <!-- Spanish (Cuba) --> + <item>es-DO</item> <!-- Spanish (Dominican Republic) --> + <item>es-EA</item> <!-- Spanish (Ceuta & Melilla) --> + <item>es-EC</item> <!-- Spanish (Ecuador) --> + <item>es-ES</item> <!-- Spanish (Spain) --> + <item>es-GQ</item> <!-- Spanish (Equatorial Guinea) --> + <item>es-GT</item> <!-- Spanish (Guatemala) --> + <item>es-HN</item> <!-- Spanish (Honduras) --> + <item>es-IC</item> <!-- Spanish (Canary Islands) --> + <item>es-MX</item> <!-- Spanish (Mexico) --> + <item>es-NI</item> <!-- Spanish (Nicaragua) --> + <item>es-PA</item> <!-- Spanish (Panama) --> + <item>es-PE</item> <!-- Spanish (Peru) --> + <item>es-PH</item> <!-- Spanish (Philippines) --> + <item>es-PR</item> <!-- Spanish (Puerto Rico) --> + <item>es-PY</item> <!-- Spanish (Paraguay) --> + <item>es-SV</item> <!-- Spanish (El Salvador) --> + <item>es-US</item> <!-- Spanish (United States) --> + <item>es-UY</item> <!-- Spanish (Uruguay) --> + <item>es-VE</item> <!-- Spanish (Venezuela) --> + <item>et-EE</item> <!-- Estonian (Estonia) --> + <item>eu-ES</item> <!-- Basque (Spain) --> + <item>ewo-CM</item> <!-- Ewondo (Cameroon) --> + <item>fa-AF</item> <!-- Persian (Afghanistan) --> + <item>fa-IR</item> <!-- Persian (Iran) --> + <item>ff-CM</item> <!-- Fulah (Cameroon) --> + <item>ff-GN</item> <!-- Fulah (Guinea) --> + <item>ff-MR</item> <!-- Fulah (Mauritania) --> + <item>ff-SN</item> <!-- Fulah (Senegal) --> + <item>fi-FI</item> <!-- Finnish (Finland) --> + <item>fil-PH</item> <!-- Filipino (Philippines) --> + <item>fo-DK</item> <!-- Faroese (Denmark) --> + <item>fo-FO</item> <!-- Faroese (Faroe Islands) --> + <item>fr-BE</item> <!-- French (Belgium) --> + <item>fr-BF</item> <!-- French (Burkina Faso) --> + <item>fr-BI</item> <!-- French (Burundi) --> + <item>fr-BJ</item> <!-- French (Benin) --> + <item>fr-BL</item> <!-- French (St. Barthélemy) --> + <item>fr-CA</item> <!-- French (Canada) --> + <item>fr-CD</item> <!-- French (Congo (DRC)) --> + <item>fr-CF</item> <!-- French (Central African Republic) --> + <item>fr-CG</item> <!-- French (Congo (Republic)) --> + <item>fr-CH</item> <!-- French (Switzerland) --> + <item>fr-CI</item> <!-- French (Côte d’Ivoire) --> + <item>fr-CM</item> <!-- French (Cameroon) --> + <item>fr-DJ</item> <!-- French (Djibouti) --> + <item>fr-DZ</item> <!-- French (Algeria) --> + <item>fr-FR</item> <!-- French (France) --> + <item>fr-GA</item> <!-- French (Gabon) --> + <item>fr-GF</item> <!-- French (French Guiana) --> + <item>fr-GN</item> <!-- French (Guinea) --> + <item>fr-GP</item> <!-- French (Guadeloupe) --> + <item>fr-GQ</item> <!-- French (Equatorial Guinea) --> + <item>fr-HT</item> <!-- French (Haiti) --> + <item>fr-KM</item> <!-- French (Comoros) --> + <item>fr-LU</item> <!-- French (Luxembourg) --> + <item>fr-MA</item> <!-- French (Morocco) --> + <item>fr-MC</item> <!-- French (Monaco) --> + <item>fr-MF</item> <!-- French (St. Martin) --> + <item>fr-MG</item> <!-- French (Madagascar) --> + <item>fr-ML</item> <!-- French (Mali) --> + <item>fr-MQ</item> <!-- French (Martinique) --> + <item>fr-MR</item> <!-- French (Mauritania) --> + <item>fr-MU</item> <!-- French (Mauritius) --> + <item>fr-NC</item> <!-- French (New Caledonia) --> + <item>fr-NE</item> <!-- French (Niger) --> + <item>fr-PF</item> <!-- French (French Polynesia) --> + <item>fr-PM</item> <!-- French (St. Pierre & Miquelon) --> + <item>fr-RE</item> <!-- French (Réunion) --> + <item>fr-RW</item> <!-- French (Rwanda) --> + <item>fr-SC</item> <!-- French (Seychelles) --> + <item>fr-SN</item> <!-- French (Senegal) --> + <item>fr-SY</item> <!-- French (Syria) --> + <item>fr-TD</item> <!-- French (Chad) --> + <item>fr-TG</item> <!-- French (Togo) --> + <item>fr-TN</item> <!-- French (Tunisia) --> + <item>fr-VU</item> <!-- French (Vanuatu) --> + <item>fr-WF</item> <!-- French (Wallis & Futuna) --> + <item>fr-YT</item> <!-- French (Mayotte) --> + <item>fur-IT</item> <!-- Friulian (Italy) --> + <item>fy-NL</item> <!-- Western Frisian (Netherlands) --> + <item>ga-IE</item> <!-- Irish (Ireland) --> + <item>gd-GB</item> <!-- Scottish Gaelic (United Kingdom) --> + <item>gl-ES</item> <!-- Galician (Spain) --> + <item>gsw-CH</item> <!-- Swiss German (Switzerland) --> + <item>gsw-FR</item> <!-- Swiss German (France) --> + <item>gsw-LI</item> <!-- Swiss German (Liechtenstein) --> + <item>gu-IN</item> <!-- Gujarati (India) --> + <item>guz-KE</item> <!-- Gusii (Kenya) --> + <item>gv-IM</item> <!-- Manx (Isle of Man) --> + <item>ha-GH</item> <!-- Hausa (Ghana) --> + <item>ha-NE</item> <!-- Hausa (Niger) --> + <item>ha-NG</item> <!-- Hausa (Nigeria) --> + <item>haw-US</item> <!-- Hawaiian (United States) --> + <item>iw-IL</item> <!-- Hebrew (Israel) --> + <item>hi-IN</item> <!-- Hindi (India) --> + <item>hr-BA</item> <!-- Croatian (Bosnia & Herzegovina) --> + <item>hr-HR</item> <!-- Croatian (Croatia) --> + <item>hsb-DE</item> <!-- Upper Sorbian (Germany) --> + <item>hu-HU</item> <!-- Hungarian (Hungary) --> + <item>hy-AM</item> <!-- Armenian (Armenia) --> + <item>in-ID</item> <!-- Indonesian (Indonesia) --> + <item>ig-NG</item> <!-- Igbo (Nigeria) --> + <item>ii-CN</item> <!-- Sichuan Yi (China) --> + <item>is-IS</item> <!-- Icelandic (Iceland) --> + <item>it-CH</item> <!-- Italian (Switzerland) --> + <item>it-IT</item> <!-- Italian (Italy) --> + <item>it-SM</item> <!-- Italian (San Marino) --> + <item>ja-JP</item> <!-- Japanese (Japan) --> + <item>jgo-CM</item> <!-- Ngomba (Cameroon) --> + <item>jmc-TZ</item> <!-- Machame (Tanzania) --> + <item>ka-GE</item> <!-- Georgian (Georgia) --> + <item>kab-DZ</item> <!-- Kabyle (Algeria) --> + <item>kam-KE</item> <!-- Kamba (Kenya) --> + <item>kde-TZ</item> <!-- Makonde (Tanzania) --> + <item>kea-CV</item> <!-- Kabuverdianu (Cape Verde) --> + <item>khq-ML</item> <!-- Koyra Chiini (Mali) --> + <item>ki-KE</item> <!-- Kikuyu (Kenya) --> + <item>kk-KZ</item> <!-- Kazakh (Kazakhstan) --> + <item>kkj-CM</item> <!-- Kako (Cameroon) --> + <item>kl-GL</item> <!-- Kalaallisut (Greenland) --> + <item>kln-KE</item> <!-- Kalenjin (Kenya) --> + <item>km-KH</item> <!-- Khmer (Cambodia) --> + <item>kn-IN</item> <!-- Kannada (India) --> + <item>ko-KP</item> <!-- Korean (North Korea) --> + <item>ko-KR</item> <!-- Korean (South Korea) --> + <item>kok-IN</item> <!-- Konkani (India) --> + <item>ks-IN</item> <!-- Kashmiri (India) --> + <item>ksb-TZ</item> <!-- Shambala (Tanzania) --> + <item>ksf-CM</item> <!-- Bafia (Cameroon) --> + <item>ksh-DE</item> <!-- Colognian (Germany) --> + <item>kw-GB</item> <!-- Cornish (United Kingdom) --> + <item>ky-KG</item> <!-- Kyrgyz (Kyrgyzstan) --> + <item>lag-TZ</item> <!-- Langi (Tanzania) --> + <item>lb-LU</item> <!-- Luxembourgish (Luxembourg) --> + <item>lg-UG</item> <!-- Ganda (Uganda) --> + <item>lkt-US</item> <!-- Lakota (United States) --> + <item>ln-AO</item> <!-- Lingala (Angola) --> + <item>ln-CD</item> <!-- Lingala (Congo (DRC)) --> + <item>ln-CF</item> <!-- Lingala (Central African Republic) --> + <item>ln-CG</item> <!-- Lingala (Congo (Republic)) --> + <item>lo-LA</item> <!-- Lao (Laos) --> + <item>lrc-IQ</item> <!-- Northern Luri (Iraq) --> + <item>lrc-IR</item> <!-- Northern Luri (Iran) --> + <item>lt-LT</item> <!-- Lithuanian (Lithuania) --> + <item>lu-CD</item> <!-- Luba-Katanga (Congo (DRC)) --> + <item>luo-KE</item> <!-- Luo (Kenya) --> + <item>luy-KE</item> <!-- Luyia (Kenya) --> + <item>lv-LV</item> <!-- Latvian (Latvia) --> + <item>mas-KE</item> <!-- Masai (Kenya) --> + <item>mas-TZ</item> <!-- Masai (Tanzania) --> + <item>mer-KE</item> <!-- Meru (Kenya) --> + <item>mfe-MU</item> <!-- Morisyen (Mauritius) --> + <item>mg-MG</item> <!-- Malagasy (Madagascar) --> + <item>mgh-MZ</item> <!-- Makhuwa-Meetto (Mozambique) --> + <item>mgo-CM</item> <!-- Metaʼ (Cameroon) --> + <item>mk-MK</item> <!-- Macedonian (Macedonia (FYROM)) --> + <item>ml-IN</item> <!-- Malayalam (India) --> + <item>mn-MN</item> <!-- Mongolian (Mongolia) --> + <item>mr-IN</item> <!-- Marathi (India) --> + <item>ms-BN</item> <!-- Malay (Brunei) --> + <item>ms-MY</item> <!-- Malay (Malaysia) --> + <item>ms-SG</item> <!-- Malay (Singapore) --> + <item>mt-MT</item> <!-- Maltese (Malta) --> + <item>mua-CM</item> <!-- Mundang (Cameroon) --> + <item>my-MM</item> <!-- Burmese (Myanmar (Burma)) --> + <item>mzn-IR</item> <!-- Mazanderani (Iran) --> + <item>naq-NA</item> <!-- Nama (Namibia) --> + <item>nb-NO</item> <!-- Norwegian BokmÃ¥l (Norway) --> + <item>nb-SJ</item> <!-- Norwegian BokmÃ¥l (Svalbard & Jan Mayen) --> + <item>nd-ZW</item> <!-- North Ndebele (Zimbabwe) --> + <item>ne-IN</item> <!-- Nepali (India) --> + <item>ne-NP</item> <!-- Nepali (Nepal) --> + <item>nl-AW</item> <!-- Dutch (Aruba) --> + <item>nl-BE</item> <!-- Dutch (Belgium) --> + <item>nl-BQ</item> <!-- Dutch (Caribbean Netherlands) --> + <item>nl-CW</item> <!-- Dutch (Curaçao) --> + <item>nl-NL</item> <!-- Dutch (Netherlands) --> + <item>nl-SR</item> <!-- Dutch (Suriname) --> + <item>nl-SX</item> <!-- Dutch (Sint Maarten) --> + <item>nmg-CM</item> <!-- Kwasio (Cameroon) --> + <item>nn-NO</item> <!-- Norwegian Nynorsk (Norway) --> + <item>nnh-CM</item> <!-- Ngiemboon (Cameroon) --> + <item>nus-SS</item> <!-- Nuer (South Sudan) --> + <item>nyn-UG</item> <!-- Nyankole (Uganda) --> + <item>om-ET</item> <!-- Oromo (Ethiopia) --> + <item>om-KE</item> <!-- Oromo (Kenya) --> + <item>or-IN</item> <!-- Oriya (India) --> + <item>os-GE</item> <!-- Ossetic (Georgia) --> + <item>os-RU</item> <!-- Ossetic (Russia) --> + <item>pa-Arab-PK</item> <!-- Punjabi (Arabic,Pakistan) --> + <item>pa-Guru-IN</item> <!-- Punjabi (Gurmukhi,India) --> + <item>pl-PL</item> <!-- Polish (Poland) --> + <item>ps-AF</item> <!-- Pashto (Afghanistan) --> + <item>pt-AO</item> <!-- Portuguese (Angola) --> + <item>pt-BR</item> <!-- Portuguese (Brazil) --> + <item>pt-CV</item> <!-- Portuguese (Cape Verde) --> + <item>pt-GW</item> <!-- Portuguese (Guinea-Bissau) --> + <item>pt-MO</item> <!-- Portuguese (Macau) --> + <item>pt-MZ</item> <!-- Portuguese (Mozambique) --> + <item>pt-PT</item> <!-- Portuguese (Portugal) --> + <item>pt-ST</item> <!-- Portuguese (São Tomé & PrÃncipe) --> + <item>pt-TL</item> <!-- Portuguese (Timor-Leste) --> + <item>qu-BO</item> <!-- Quechua (Bolivia) --> + <item>qu-EC</item> <!-- Quechua (Ecuador) --> + <item>qu-PE</item> <!-- Quechua (Peru) --> + <item>rm-CH</item> <!-- Romansh (Switzerland) --> + <item>rn-BI</item> <!-- Rundi (Burundi) --> + <item>ro-MD</item> <!-- Romanian (Moldova) --> + <item>ro-RO</item> <!-- Romanian (Romania) --> + <item>rof-TZ</item> <!-- Rombo (Tanzania) --> + <item>ru-BY</item> <!-- Russian (Belarus) --> + <item>ru-KG</item> <!-- Russian (Kyrgyzstan) --> + <item>ru-KZ</item> <!-- Russian (Kazakhstan) --> + <item>ru-MD</item> <!-- Russian (Moldova) --> + <item>ru-RU</item> <!-- Russian (Russia) --> + <item>ru-UA</item> <!-- Russian (Ukraine) --> + <item>rw-RW</item> <!-- Kinyarwanda (Rwanda) --> + <item>rwk-TZ</item> <!-- Rwa (Tanzania) --> + <item>sah-RU</item> <!-- Sakha (Russia) --> + <item>saq-KE</item> <!-- Samburu (Kenya) --> + <item>sbp-TZ</item> <!-- Sangu (Tanzania) --> + <item>se-FI</item> <!-- Northern Sami (Finland) --> + <item>se-NO</item> <!-- Northern Sami (Norway) --> + <item>se-SE</item> <!-- Northern Sami (Sweden) --> + <item>seh-MZ</item> <!-- Sena (Mozambique) --> + <item>ses-ML</item> <!-- Koyraboro Senni (Mali) --> + <item>sg-CF</item> <!-- Sango (Central African Republic) --> + <item>shi-Latn-MA</item> <!-- Tachelhit (Latin,Morocco) --> + <item>shi-Tfng-MA</item> <!-- Tachelhit (Tifinagh,Morocco) --> + <item>si-LK</item> <!-- Sinhala (Sri Lanka) --> + <item>sk-SK</item> <!-- Slovak (Slovakia) --> + <item>sl-SI</item> <!-- Slovenian (Slovenia) --> + <item>smn-FI</item> <!-- Inari Sami (Finland) --> + <item>sn-ZW</item> <!-- Shona (Zimbabwe) --> + <item>so-DJ</item> <!-- Somali (Djibouti) --> + <item>so-ET</item> <!-- Somali (Ethiopia) --> + <item>so-KE</item> <!-- Somali (Kenya) --> + <item>so-SO</item> <!-- Somali (Somalia) --> + <item>sq-AL</item> <!-- Albanian (Albania) --> + <item>sq-MK</item> <!-- Albanian (Macedonia (FYROM)) --> + <item>sq-XK</item> <!-- Albanian (Kosovo) --> + <item>sr-Cyrl-BA</item> <!-- Serbian (Cyrillic,Bosnia & Herzegovina) --> + <item>sr-Cyrl-ME</item> <!-- Serbian (Cyrillic,Montenegro) --> + <item>sr-Cyrl-RS</item> <!-- Serbian (Cyrillic,Serbia) --> + <item>sr-Cyrl-XK</item> <!-- Serbian (Cyrillic,Kosovo) --> + <item>sr-Latn-BA</item> <!-- Serbian (Latin,Bosnia & Herzegovina) --> + <item>sr-Latn-ME</item> <!-- Serbian (Latin,Montenegro) --> + <item>sr-Latn-RS</item> <!-- Serbian (Latin,Serbia) --> + <item>sr-Latn-XK</item> <!-- Serbian (Latin,Kosovo) --> + <item>sv-AX</item> <!-- Swedish (Ã…land Islands) --> + <item>sv-FI</item> <!-- Swedish (Finland) --> + <item>sv-SE</item> <!-- Swedish (Sweden) --> + <item>sw-CD</item> <!-- Swahili (Congo (DRC)) --> + <item>sw-KE</item> <!-- Swahili (Kenya) --> + <item>sw-TZ</item> <!-- Swahili (Tanzania) --> + <item>sw-UG</item> <!-- Swahili (Uganda) --> + <item>ta-IN</item> <!-- Tamil (India) --> + <item>ta-LK</item> <!-- Tamil (Sri Lanka) --> + <item>ta-MY</item> <!-- Tamil (Malaysia) --> + <item>ta-SG</item> <!-- Tamil (Singapore) --> + <item>te-IN</item> <!-- Telugu (India) --> + <item>teo-KE</item> <!-- Teso (Kenya) --> + <item>teo-UG</item> <!-- Teso (Uganda) --> + <item>th-TH</item> <!-- Thai (Thailand) --> + <item>ti-ER</item> <!-- Tigrinya (Eritrea) --> + <item>ti-ET</item> <!-- Tigrinya (Ethiopia) --> + <item>to-TO</item> <!-- Tongan (Tonga) --> + <item>tr-CY</item> <!-- Turkish (Cyprus) --> + <item>tr-TR</item> <!-- Turkish (Turkey) --> + <item>twq-NE</item> <!-- Tasawaq (Niger) --> + <item>tzm-MA</item> <!-- Central Atlas Tamazight (Morocco) --> + <item>ug-CN</item> <!-- Uyghur (China) --> + <item>uk-UA</item> <!-- Ukrainian (Ukraine) --> + <item>ur-IN</item> <!-- Urdu (India) --> + <item>ur-PK</item> <!-- Urdu (Pakistan) --> + <item>uz-Arab-AF</item> <!-- Uzbek (Arabic,Afghanistan) --> + <item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic,Uzbekistan) --> + <item>uz-Latn-UZ</item> <!-- Uzbek (Latin,Uzbekistan) --> + <item>vai-Latn-LR</item> <!-- Vai (Latin,Liberia) --> + <item>vai-Vaii-LR</item> <!-- Vai (Vai,Liberia) --> + <item>vi-VN</item> <!-- Vietnamese (Vietnam) --> + <item>vun-TZ</item> <!-- Vunjo (Tanzania) --> + <item>wae-CH</item> <!-- Walser (Switzerland) --> + <item>xog-UG</item> <!-- Soga (Uganda) --> + <item>yav-CM</item> <!-- Yangben (Cameroon) --> + <item>yo-BJ</item> <!-- Yoruba (Benin) --> + <item>yo-NG</item> <!-- Yoruba (Nigeria) --> + <item>zgh-MA</item> <!-- Standard Moroccan Tamazight (Morocco) --> + <item>zh-Hans-CN</item> <!-- Chinese (Simplified Han,China) --> + <item>zh-Hans-HK</item> <!-- Chinese (Simplified Han,Hong Kong) --> + <item>zh-Hans-MO</item> <!-- Chinese (Simplified Han,Macau) --> + <item>zh-Hans-SG</item> <!-- Chinese (Simplified Han,Singapore) --> + <item>zh-Hant-HK</item> <!-- Chinese (Traditional Han,Hong Kong) --> + <item>zh-Hant-MO</item> <!-- Chinese (Traditional Han,Macau) --> + <item>zh-Hant-TW</item> <!-- Chinese (Traditional Han,Taiwan) --> + <item>zu-ZA</item> <!-- Zulu (South Africa) --> + </string-array> + +</resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 4843879a2dba..a127d94691eb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3966,25 +3966,6 @@ <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description --> <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string> - - <!-- [CHAR LIMIT=100] Notification importance slider title --> - <string name="notification_importance_title">Importance</string> - - <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description --> - <string name="notification_importance_blocked">Blocked: Never show these notifications</string> - - <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description --> - <string name="notification_importance_low">Low: Silently show at the bottom of the notification list</string> - - <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description --> - <string name="notification_importance_default">Normal: Silently show these notifications</string> - - <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description --> - <string name="notification_importance_high">High: Show at the top of the notifications list and make sound</string> - - <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description --> - <string name="notification_importance_max">Urgent: Peek onto the screen and make sound</string> - <!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] --> <plurals name="zen_mode_duration_minutes_summary"> <item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f257f1455cb2..3ee1ca9a792a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1124,6 +1124,7 @@ <java-symbol type="array" name="sim_colors" /> <java-symbol type="array" name="special_locale_codes" /> <java-symbol type="array" name="special_locale_names" /> + <java-symbol type="array" name="supported_locales" /> <java-symbol type="array" name="config_cdma_dun_supported_types" /> <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" /> <java-symbol type="array" name="config_disabledUntilUsedPreinstalledCarrierApps" /> @@ -2091,12 +2092,6 @@ <java-symbol type="array" name="config_system_condition_providers" /> <java-symbol type="string" name="muted_by" /> <java-symbol type="string" name="zen_mode_alarm" /> - <java-symbol type="string" name="notification_importance_blocked" /> - <java-symbol type="string" name="notification_importance_low" /> - <java-symbol type="string" name="notification_importance_default" /> - <java-symbol type="string" name="notification_importance_high" /> - <java-symbol type="string" name="notification_importance_max" /> - <java-symbol type="string" name="notification_importance_title" /> <java-symbol type="string" name="select_day" /> <java-symbol type="string" name="select_year" /> diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java new file mode 100644 index 000000000000..49ae10401983 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * Tests for {@link IndentingPrintWriter}. + */ +public class LineBreakBufferedWriterTest extends TestCase { + + private ByteArrayOutputStream mStream; + private RecordingWriter mWriter; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mWriter = new RecordingWriter(); + } + + public void testLessThanBufferSize() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 1000); + + lw.println("Hello"); + lw.println("World"); + lw.println("Test"); + lw.flush(); + + assertOutput("Hello\nWorld\nTest\n"); + } + + public void testMoreThanBufferSizeNoLineBreaks() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal = "aaaaaaaaaaaaaaa"; + lw.print(literal); + lw.print(literal); + lw.flush(); + + // Have to manually inspect output. + List<String> result = mWriter.getStrings(); + // Expect two strings. + assertEquals(2, result.size()); + // Expect the strings to sum up to the original input. + assertEquals(2 * literal.length(), result.get(0).length() + result.get(1).length()); + // Strings should only be a. + for (String s : result) { + for (int i = 0; i < s.length(); i++) { + assertEquals('a', s.charAt(i)); + } + } + } + + public void testMoreThanBufferSizeNoLineBreaksSingleString() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal = "aaaaaaaaaaaaaaa"; + lw.print(literal + literal); + lw.flush(); + + // Have to manually inspect output. + List<String> result = mWriter.getStrings(); + // Expect two strings. + assertEquals(2, result.size()); + // Expect the strings to sum up to the original input. + assertEquals(2 * literal.length(), result.get(0).length() + result.get(1).length()); + // Strings should only be a. + for (String s : result) { + for (int i = 0; i < s.length(); i++) { + assertEquals('a', s.charAt(i)); + } + } + } + + public void testMoreThanBufferSizeLineBreakBefore() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal1 = "aaaaaaaaaa\nbbbb"; + String literal2 = "cccccccccc"; + lw.print(literal1); + lw.print(literal2); + lw.flush(); + + assertOutput("aaaaaaaaaa", "bbbbcccccccccc"); + } + + public void testMoreThanBufferSizeLineBreakBeforeSingleString() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal1 = "aaaaaaaaaa\nbbbb"; + String literal2 = "cccccccccc"; + lw.print(literal1 + literal2); + lw.flush(); + + assertOutput("aaaaaaaaaa", "bbbbcccccccccc"); + } + + public void testMoreThanBufferSizeLineBreakNew() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal1 = "aaaaaaaaaabbbbb"; + String literal2 = "c\nd\nddddddddd"; + lw.print(literal1); + lw.print(literal2); + lw.flush(); + + assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd"); + } + + public void testMoreThanBufferSizeLineBreakBeforeAndNew() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal1 = "aaaaaaaaaa\nbbbbb"; + String literal2 = "c\nd\nddddddddd"; + lw.print(literal1); + lw.print(literal2); + lw.flush(); + + assertOutput("aaaaaaaaaa\nbbbbbc\nd", "ddddddddd"); + } + + public void testMoreThanBufferSizeInt() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15); + + int literal1 = 1234567890; + int literal2 = 987654321; + lw.print(literal1); + lw.print(literal2); + lw.flush(); + + assertOutput("123456789098765", "4321"); + } + + public void testMoreThanBufferSizeChar() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15); + + for(int i = 0; i < 10; i++) { + lw.print('$'); + } + for(int i = 0; i < 10; i++) { + lw.print('%'); + } + lw.flush(); + + assertOutput("$$$$$$$$$$%%%%%", "%%%%%"); + } + + public void testMoreThanBufferSizeLineBreakNewChars() { + final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20); + + String literal1 = "aaaaaaaaaabbbbb"; + String literal2 = "c\nd\nddddddddd"; + lw.print(literal1.toCharArray()); + lw.print(literal2.toCharArray()); + lw.flush(); + + assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd"); + } + + private void assertOutput(String... golden) { + List<String> goldList = createTestGolden(golden); + assertEquals(goldList, mWriter.getStrings()); + } + + private static List<String> createTestGolden(String... args) { + List<String> ret = new ArrayList<String>(); + for (String s : args) { + ret.add(s); + } + return ret; + } + + // A writer recording calls to write. + private final static class RecordingWriter extends Writer { + + private List<String> strings = new ArrayList<String>(); + + public RecordingWriter() { + } + + public List<String> getStrings() { + return strings; + } + + @Override + public void write(char[] cbuf, int off, int len) { + strings.add(new String(cbuf, off, len)); + } + + @Override + public void flush() { + // Ignore. + } + + @Override + public void close() { + // Ignore. + } + } +} diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 02ddae6845bc..9546c8dba734 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -139,6 +139,9 @@ <!-- Adding Quick Settings tiles --> <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" /> + <!-- Block notifications inline notifications --> + <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <application android:name=".SystemUIApplication" android:persistent="true" diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml index f15c97ef6694..3cdee640dd26 100644 --- a/packages/SystemUI/res/layout/notification_guts.xml +++ b/packages/SystemUI/res/layout/notification_guts.xml @@ -139,7 +139,9 @@ </FrameLayout> - <RadioGroup android:layout_width="wrap_content" + <RadioGroup + android:id="@+id/apply_to" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="8dp"> <RadioButton android:id="@+id/apply_to_topic" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index 57db80a0744b..79236be87e5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import android.annotation.IdRes; import android.app.INotificationManager; import android.app.Notification; import android.content.Context; @@ -30,6 +31,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.RadioButton; +import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.TextView; @@ -101,24 +103,51 @@ public class NotificationGuts extends LinearLayout { ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString( com.android.internal.R.string.default_notification_topic_label)) : sbn.getNotification().getTopic(); + boolean doesAppUseTopics = false; + try { + doesAppUseTopics = sINM.doesAppUseTopics(sbn.getPackageName(), sbn.getUid()); + } catch (RemoteException e) {} + final boolean appUsesTopics = doesAppUseTopics; final RadioButton applyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic); - if (sbn.getNotification().getTopic() != null) { - applyToTopic.setVisibility(View.VISIBLE); - applyToTopic.setChecked(true); - applyToTopic.setText(mContext.getString(R.string.apply_to_topic, topic.getLabel())); - row.findViewById(R.id.apply_to_app).setVisibility(View.VISIBLE); - } - + applyToTopic.setChecked(true); + final View applyToApp = row.findViewById(R.id.apply_to_app); final TextView topicSummary = ((TextView) row.findViewById(R.id.summary)); final TextView topicTitle = ((TextView) row.findViewById(R.id.title)); - SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar); + final SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar); + final RadioGroup applyTo = (RadioGroup) row.findViewById(R.id.apply_to); + applyTo.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { + try { + switch (checkedId) { + case R.id.apply_to_topic: + sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic, + seekBar.getProgress()); + break; + default: + sINM.setAppImportance(sbn.getPackageName(), sbn.getUid(), + seekBar.getProgress()); + } + } catch (RemoteException e) { + // :( + } + } + }); + seekBar.setMax(4); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { updateTitleAndSummary(progress); if (fromUser) { + if (appUsesTopics) { + applyToTopic.setVisibility(View.VISIBLE); + + applyToTopic.setText( + mContext.getString(R.string.apply_to_topic, topic.getLabel())); + applyToApp.setVisibility(View.VISIBLE); + } try { if (applyToTopic.isChecked()) { sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3e7b963ddd98..de0a23aa723f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -53,6 +53,7 @@ import com.android.server.am.ActivityStack.ActivityState; import com.android.server.firewall.IntentFirewall; import com.android.server.pm.Installer; import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.vr.VrManagerInternal; import com.android.server.wm.AppTransition; import com.android.server.wm.WindowManagerService; @@ -1443,6 +1444,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int IDLE_UIDS_MSG = 60; static final int SYSTEM_USER_UNLOCK_MSG = 61; static final int LOG_STACK_STATE = 62; + static final int VR_MODE_CHANGE_MSG = 63; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -2157,6 +2159,10 @@ public final class ActivityManagerService extends ActivityManagerNative mStackSupervisor.logStackState(); } } break; + case VR_MODE_CHANGE_MSG: { + VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); + vrService.setVrMode(msg.arg1 != 0); + } break; } } }; @@ -2781,6 +2787,7 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setFocusedApp(r.appToken, true); } applyUpdateLockStateLocked(r); + applyUpdateVrModeLocked(r); if (mFocusedActivity.userId != mLastFocusedUserId) { mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG); mHandler.obtainMessage( @@ -2877,6 +2884,11 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r)); } + final void applyUpdateVrModeLocked(ActivityRecord r) { + mHandler.sendMessage( + mHandler.obtainMessage(VR_MODE_CHANGE_MSG, (r.isVrActivity) ? 1 : 0, 0)); + } + final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; @@ -11750,6 +11762,26 @@ public final class ActivityManagerService extends ActivityManagerNative } } + @Override + public void setVrMode(IBinder token, boolean enabled) { + if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) { + throw new UnsupportedOperationException("VR mode not supported on this device!"); + } + + synchronized(this) { + final ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r == null) { + throw new IllegalArgumentException(); + } + r.isVrActivity = enabled; + + // Update associated state if this activity is currently focused + if (r == mFocusedActivity) { + applyUpdateVrModeLocked(r); + } + } + } + public boolean isTopActivityImmersive() { enforceNotIsolatedCaller("startActivity"); synchronized (this) { diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 3da0f8d9c778..4d9120b09478 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -181,6 +181,7 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity + boolean isVrActivity; // is the activity running in VR mode? ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>(); String stringName; // for caching of toString(). @@ -317,6 +318,7 @@ final class ActivityRecord { pw.print(" forceNewConfig="); pw.println(forceNewConfig); pw.print(prefix); pw.print("mActivityType="); pw.println(activityTypeToString(mActivityType)); + pw.print(prefix); pw.print("vrMode="); pw.println(isVrActivity); if (displayStartTime != 0 || startTime != 0) { pw.print(prefix); pw.print("displayStartTime="); if (displayStartTime == 0) pw.print("0"); @@ -650,6 +652,7 @@ final class ActivityRecord { } immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0; + isVrActivity = (aInfo.flags & ActivityInfo.FLAG_ENABLE_VR_MODE) != 0; } else { realActivity = null; taskAffinity = null; @@ -661,6 +664,7 @@ final class ActivityRecord { noDisplay = false; mActivityType = APPLICATION_ACTIVITY_TYPE; immersive = false; + isVrActivity = false; } } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 5426b72c2efb..43d4e775a098 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1222,7 +1222,7 @@ final class UserController { } private boolean isCurrentUserLocked(int userId) { - return mCurrentUserId == userId || mTargetUserId == userId; + return userId == getCurrentOrTargetUserIdLocked(); } int setTargetUserIdLocked(int targetUserId) { diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index d5773690f122..b7662daffec4 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -42,6 +42,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Slog; @@ -53,6 +54,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map.Entry; import java.util.Objects; import java.util.Set; @@ -93,6 +95,8 @@ abstract public class ManagedServices { // List of packages in restored setting across all mUserProfiles, for quick // filtering upon package updates. private ArraySet<String> mRestoredPackages = new ArraySet<>(); + // State of current service categories + private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>(); // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a @@ -262,6 +266,46 @@ abstract public class ManagedServices { } } + public void setCategoryState(String category, boolean enabled) { + synchronized (mMutex) { + final Boolean previous = mCategoryEnabled.put(category, enabled); + if (!(previous == null || previous != enabled)) { + return; + } + + // State changed + if (DEBUG) { + Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "category " + category); + } + + final int[] userIds = mUserProfiles.getCurrentProfileIds(); + for (int userId : userIds) { + final Set<ComponentName> componentNames = queryPackageForServices(null, + userId, category); + + // Disallow services not enabled in Settings + final ArraySet<ComponentName> userComponents = + loadComponentNamesFromSetting(mConfig.secureSettingName, userId); + if (userComponents == null) { + componentNames.clear(); + } else { + componentNames.retainAll(userComponents); + } + + if (DEBUG) { + Slog.d(TAG, "Components for category " + category + ": " + componentNames); + } + for (ComponentName c : componentNames) { + if (enabled) { + registerServiceLocked(c, userId); + } else { + unregisterServiceLocked(c, userId); + } + } + } + + } + } private void rebuildRestoredPackages() { mRestoredPackages.clear(); @@ -283,9 +327,9 @@ abstract public class ManagedServices { int userId) { final ContentResolver cr = mContext.getContentResolver(); String settingValue = Settings.Secure.getStringForUser( - cr, - settingName, - userId); + cr, + settingName, + userId); if (TextUtils.isEmpty(settingValue)) return null; String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR); @@ -314,10 +358,10 @@ abstract public class ManagedServices { TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames); final ContentResolver cr = mContext.getContentResolver(); Settings.Secure.putStringForUser( - cr, - settingName, - value, - userId); + cr, + settingName, + value, + userId); } /** @@ -333,12 +377,20 @@ abstract public class ManagedServices { } protected Set<ComponentName> queryPackageForServices(String packageName, int userId) { + return queryPackageForServices(packageName, userId, null); + } + + protected Set<ComponentName> queryPackageForServices(String packageName, int userId, + String category) { Set<ComponentName> installed = new ArraySet<>(); final PackageManager pm = mContext.getPackageManager(); Intent queryIntent = new Intent(mConfig.serviceInterface); if (!TextUtils.isEmpty(packageName)) { queryIntent.setPackage(packageName); } + if (category != null) { + queryIntent.addCategory(category); + } List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( queryIntent, PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, @@ -353,9 +405,9 @@ abstract public class ManagedServices { ComponentName component = new ComponentName(info.packageName, info.name); if (!mConfig.bindPermission.equals(info.permission)) { Slog.w(TAG, "Skipping " + getCaption() + " service " - + info.packageName + "/" + info.name - + ": it does not require the permission " - + mConfig.bindPermission); + + info.packageName + "/" + info.name + + ": it does not require the permission " + + mConfig.bindPermission); continue; } installed.add(component); @@ -449,6 +501,16 @@ abstract public class ManagedServices { } final ArrayList<ComponentName> add = new ArrayList<>(userComponents); + + // Remove components from disabled categories so that those services aren't run. + for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) { + if (!e.getValue()) { + Set<ComponentName> c = queryPackageForServices(null, userIds[i], + e.getKey()); + add.removeAll(c); + } + } + toAdd.put(userIds[i], add); newEnabled.addAll(userComponents); @@ -488,93 +550,97 @@ abstract public class ManagedServices { * Version of registerService that takes the name of a service component to bind to. */ private void registerService(final ComponentName name, final int userid) { + synchronized (mMutex) { + registerServiceLocked(name, userid); + } + } + + private void registerServiceLocked(final ComponentName name, final int userid) { if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid); - synchronized (mMutex) { - final String servicesBindingTag = name.toString() + "/" + userid; - if (mServicesBinding.contains(servicesBindingTag)) { - // stop registering this thing already! we're working on it - return; - } - mServicesBinding.add(servicesBindingTag); + final String servicesBindingTag = name.toString() + "/" + userid; + if (mServicesBinding.contains(servicesBindingTag)) { + // stop registering this thing already! we're working on it + return; + } + mServicesBinding.add(servicesBindingTag); - final int N = mServices.size(); - for (int i = N - 1; i >= 0; i--) { - final ManagedServiceInfo info = mServices.get(i); - if (name.equals(info.component) - && info.userid == userid) { - // cut old connections - if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": " - + info.service); - removeServiceLocked(i); - if (info.connection != null) { - mContext.unbindService(info.connection); - } + final int N = mServices.size(); + for (int i = N - 1; i >= 0; i--) { + final ManagedServiceInfo info = mServices.get(i); + if (name.equals(info.component) + && info.userid == userid) { + // cut old connections + if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": " + + info.service); + removeServiceLocked(i); + if (info.connection != null) { + mContext.unbindService(info.connection); } } + } - Intent intent = new Intent(mConfig.serviceInterface); - intent.setComponent(name); + Intent intent = new Intent(mConfig.serviceInterface); + intent.setComponent(name); - intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel); + intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel); - final PendingIntent pendingIntent = PendingIntent.getActivity( - mContext, 0, new Intent(mConfig.settingsAction), 0); - intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent); + final PendingIntent pendingIntent = PendingIntent.getActivity( + mContext, 0, new Intent(mConfig.settingsAction), 0); + intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent); - ApplicationInfo appInfo = null; - try { - appInfo = mContext.getPackageManager().getApplicationInfo( - name.getPackageName(), 0); - } catch (NameNotFoundException e) { - // Ignore if the package doesn't exist we won't be able to bind to the service. - } - final int targetSdkVersion = - appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE; + ApplicationInfo appInfo = null; + try { + appInfo = mContext.getPackageManager().getApplicationInfo( + name.getPackageName(), 0); + } catch (NameNotFoundException e) { + // Ignore if the package doesn't exist we won't be able to bind to the service. + } + final int targetSdkVersion = + appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE; - try { - if (DEBUG) Slog.v(TAG, "binding: " + intent); - ServiceConnection serviceConnection = new ServiceConnection() { - IInterface mService; - - @Override - public void onServiceConnected(ComponentName name, IBinder binder) { - boolean added = false; - ManagedServiceInfo info = null; - synchronized (mMutex) { - mServicesBinding.remove(servicesBindingTag); - try { - mService = asInterface(binder); - info = newServiceInfo(mService, name, - userid, false /*isSystem*/, this, targetSdkVersion); - binder.linkToDeath(info, 0); - added = mServices.add(info); - } catch (RemoteException e) { - // already dead - } - } - if (added) { - onServiceAdded(info); + try { + if (DEBUG) Slog.v(TAG, "binding: " + intent); + ServiceConnection serviceConnection = new ServiceConnection() { + IInterface mService; + + @Override + public void onServiceConnected(ComponentName name, IBinder binder) { + boolean added = false; + ManagedServiceInfo info = null; + synchronized (mMutex) { + mServicesBinding.remove(servicesBindingTag); + try { + mService = asInterface(binder); + info = newServiceInfo(mService, name, + userid, false /*isSystem*/, this, targetSdkVersion); + binder.linkToDeath(info, 0); + added = mServices.add(info); + } catch (RemoteException e) { + // already dead } } - - @Override - public void onServiceDisconnected(ComponentName name) { - Slog.v(TAG, getCaption() + " connection lost: " + name); + if (added) { + onServiceAdded(info); } - }; - if (!mContext.bindServiceAsUser(intent, - serviceConnection, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, - new UserHandle(userid))) { - mServicesBinding.remove(servicesBindingTag); - Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); - return; } - } catch (SecurityException ex) { - Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex); + + @Override + public void onServiceDisconnected(ComponentName name) { + Slog.v(TAG, getCaption() + " connection lost: " + name); + } + }; + if (!mContext.bindServiceAsUser(intent, + serviceConnection, + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, + new UserHandle(userid))) { + mServicesBinding.remove(servicesBindingTag); + Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); return; } + } catch (SecurityException ex) { + Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex); + return; } } @@ -583,20 +649,24 @@ abstract public class ManagedServices { */ private void unregisterService(ComponentName name, int userid) { synchronized (mMutex) { - final int N = mServices.size(); - for (int i = N - 1; i >= 0; i--) { - final ManagedServiceInfo info = mServices.get(i); - if (name.equals(info.component) - && info.userid == userid) { - removeServiceLocked(i); - if (info.connection != null) { - try { - mContext.unbindService(info.connection); - } catch (IllegalArgumentException ex) { - // something happened to the service: we think we have a connection - // but it's bogus. - Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex); - } + unregisterServiceLocked(name, userid); + } + } + + private void unregisterServiceLocked(ComponentName name, int userid) { + final int N = mServices.size(); + for (int i = N - 1; i >= 0; i--) { + final ManagedServiceInfo info = mServices.get(i); + if (name.equals(info.component) + && info.userid == userid) { + removeServiceLocked(i); + if (info.connection != null) { + try { + mContext.unbindService(info.connection); + } catch (IllegalArgumentException ex) { + // something happened to the service: we think we have a connection + // but it's bogus. + Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex); } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0bfbd7f5cd9f..c6df83ae9165 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -124,6 +124,9 @@ import com.android.server.lights.LightsManager; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import com.android.server.notification.ManagedServices.UserProfiles; import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.vr.VrManagerInternal; +import com.android.server.vr.VrStateListener; + import libcore.io.IoUtils; import org.json.JSONArray; import org.json.JSONException; @@ -206,6 +209,8 @@ public class NotificationManagerService extends SystemService { AudioManagerInternal mAudioManagerInternal; StatusBarManagerInternal mStatusBar; Vibrator mVibrator; + private VrManagerInternal mVrManagerInternal; + private final NotificationVrListener mVrListener = new NotificationVrListener(); final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; @@ -816,6 +821,14 @@ public class NotificationManagerService extends SystemService { } } + private final class NotificationVrListener extends VrStateListener { + @Override + public void onVrStateChanged(final boolean enabled) { + mListeners.setCategoryState(NotificationListenerService.CATEGORY_VR_NOTIFICATIONS, + enabled); + } + } + private SettingsObserver mSettingsObserver; private ZenModeHelper mZenModeHelper; @@ -1004,6 +1017,8 @@ public class NotificationManagerService extends SystemService { // Grab our optional AudioService mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManagerInternal = getLocalService(AudioManagerInternal.class); + mVrManagerInternal = getLocalService(VrManagerInternal.class); + mVrManagerInternal.registerListener(mVrListener); mZenModeHelper.onSystemReady(); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to @@ -1251,10 +1266,18 @@ public class NotificationManagerService extends SystemService { @Override public void setAppImportance(String pkg, int uid, int importance) { enforceSystemOrSystemUI("Caller not system or systemui"); + setNotificationsEnabledForPackageImpl(pkg, uid, + importance != NotificationListenerService.Ranking.IMPORTANCE_NONE); mRankingHelper.setAppImportance(pkg, uid, importance); savePolicyFile(); } + @Override + public boolean doesAppUseTopics(String pkg, int uid) { + enforceSystemOrSystemUI("Caller not system or systemui"); + return mRankingHelper.doesAppUseTopics(pkg, uid); + } + /** * System-only API for getting a list of current (i.e. not cleared) notifications. * diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index a6c9b0d946e2..9b10ef2f0fa3 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -37,4 +37,6 @@ public interface RankingConfig { int getTopicImportance(String packageName, int uid, Notification.Topic topic); void setAppImportance(String packageName, int uid, int importance); + + boolean doesAppUseTopics(String packageName, int uid); } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 32c0ce24dc20..3287f67a6b86 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -170,6 +170,7 @@ public class RankingHelper implements RankingConfig { } else { r = getOrCreateRecord(name, uid); } + r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); // Migrate package level settings to the default topic. // Might be overwritten by parseTopics. @@ -441,6 +442,18 @@ public class RankingHelper implements RankingConfig { updateConfig(); } + @Override + public boolean doesAppUseTopics(String pkgName, int uid) { + final Record r = getOrCreateRecord(pkgName, uid); + int numTopics = r.topics.size(); + if (numTopics == 0 + || (numTopics == 1 && r.topics.containsKey(Notification.TOPIC_DEFAULT))) { + return false; + } else { + return true; + } + } + private Topic getOrCreateTopic(Record r, Notification.Topic topic) { if (topic == null) { topic = createDefaultTopic(); diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java new file mode 100644 index 000000000000..42db364e6acc --- /dev/null +++ b/services/core/java/com/android/server/vr/VrManagerInternal.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.vr; + +/** + * VR mode local system service interface. + * + * @hide Only for use within system server. + */ +public abstract class VrManagerInternal { + + /** + * Return current VR mode state. + * + * @return {@code true} if VR mode is enabled. + */ + public abstract boolean isInVrMode(); + + /** + * Set the current VR mode state. + * + * @param enabled {@code true} to enable VR mode. + */ + public abstract void setVrMode(boolean enabled); + + /** + * Add a listener for VR mode state changes. + * <p> + * This listener will immediately be called with the current VR mode state. + * </p> + * @param listener the listener instance to add. + */ + public abstract void registerListener(VrStateListener listener); + + /** + * Remove the listener from the current set of listeners. + * + * @param listener the listener to remove. + */ + public abstract void unregisterListener(VrStateListener listener); + +} diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java new file mode 100644 index 000000000000..9a55e7f47dac --- /dev/null +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.vr; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.server.SystemService; + +import java.util.ArrayList; + +/** + * Service tracking whether VR mode is active, and notifying listening system services of state + * changes. + * + * {@hide} + */ +public class VrManagerService extends SystemService { + + public static final boolean DEBUG = false; + public static final String TAG = "VrManagerService"; + + private final Object mLock = new Object(); + private boolean mVrModeEnabled = false; + private ArraySet<VrStateListener> mListeners = new ArraySet<>(); + + private final class LocalService extends VrManagerInternal { + @Override + public boolean isInVrMode() { + return VrManagerService.this.getVrMode(); + } + + @Override + public void setVrMode(boolean enabled) { + VrManagerService.this.setVrMode(enabled); + } + + @Override + public void registerListener(VrStateListener listener) { + VrManagerService.this.addListener(listener); + } + + @Override + public void unregisterListener(VrStateListener listener) { + VrManagerService.this.removeListener(listener); + } + } + + public VrManagerService(Context context) { + super(context); + } + + @Override + public void onStart() { + publishLocalService(VrManagerInternal.class, new LocalService()); + } + + private void addListener(VrStateListener listener) { + synchronized (mLock) { + mListeners.add(listener); + } + } + + private void removeListener(VrStateListener listener) { + synchronized (mLock) { + mListeners.remove(listener); + } + } + + private void setVrMode(boolean enabled) { + synchronized (mLock) { + if (mVrModeEnabled != enabled) { + mVrModeEnabled = enabled; + if (DEBUG) Slog.d(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); + onVrModeChangedLocked(); + } + } + } + + private boolean getVrMode() { + synchronized (mLock) { + return mVrModeEnabled; + } + } + + /** + * Notify system services of VR mode change. + */ + private void onVrModeChangedLocked() { + for (VrStateListener l : mListeners) { + l.onVrStateChanged(mVrModeEnabled); + } + } +} diff --git a/services/core/java/com/android/server/vr/VrStateListener.java b/services/core/java/com/android/server/vr/VrStateListener.java new file mode 100644 index 000000000000..b8af4b2d4425 --- /dev/null +++ b/services/core/java/com/android/server/vr/VrStateListener.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.vr; + +/** + * Listener for state changes in VrManagerService, + */ +public abstract class VrStateListener { + + /** + * Called when the VR mode state changes. + * + * @param enabled {@code true} if VR mode is enabled. + */ + public abstract void onVrStateChanged(boolean enabled); +} diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 498259f4cfa6..c63618527910 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -74,6 +74,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; @@ -606,7 +607,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { final boolean fullscreenTask = task == null || task.isFullscreen(); final boolean freeformWorkspace = task != null && task.inFreeformWorkspace(); - if (fullscreenTask || isChildWindow()) { + if (fullscreenTask || (isChildWindow() + && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) { // We use the parent frame as the containing frame for fullscreen and child windows mContainingFrame.set(pf); mDisplayFrame.set(df); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index fb5f21ab9ca6..3db8376e5fca 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -89,14 +89,13 @@ import com.android.server.trust.TrustManagerService; import com.android.server.tv.TvInputManagerService; import com.android.server.twilight.TwilightService; import com.android.server.usage.UsageStatsService; -import com.android.server.usb.UsbService; +import com.android.server.vr.VrManagerService; import com.android.server.wallpaper.WallpaperManagerService; import com.android.server.webkit.WebViewUpdateService; import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; -import java.io.File; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; @@ -447,6 +446,7 @@ public final class SystemServer { ConsumerIrService consumerIr = null; MmsServiceBroker mmsService = null; EntropyMixer entropyMixer = null; + VrManagerService vrManagerService = null; boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false); boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false); @@ -532,6 +532,10 @@ public final class SystemServer { ServiceManager.addService(Context.INPUT_SERVICE, inputManager); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + traceBeginAndSlog("StartVrManagerService"); + mSystemServiceManager.startService(VrManagerService.class); + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + mActivityManagerService.setWindowManager(wm); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); |