summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--api/current.txt4
-rw-r--r--api/system-current.txt4
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java2
-rw-r--r--core/java/android/app/ActionBar.java5
-rw-r--r--core/java/android/app/Activity.java4
-rw-r--r--core/java/android/app/AppOpsManager.java30
-rw-r--r--core/java/android/app/assist/AssistStructure.java2
-rw-r--r--core/java/android/content/Intent.java7
-rw-r--r--core/java/android/hardware/usb/IUsbManager.aidl11
-rw-r--r--core/java/android/hardware/usb/UsbManager.java106
-rw-r--r--core/java/android/hardware/usb/UsbPort.aidl19
-rw-r--r--core/java/android/hardware/usb/UsbPort.java238
-rw-r--r--core/java/android/hardware/usb/UsbPortStatus.aidl19
-rw-r--r--core/java/android/hardware/usb/UsbPortStatus.java144
-rw-r--r--core/java/android/os/BatteryStats.java10
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/PowerManager.java12
-rw-r--r--core/java/android/os/storage/StorageManager.java17
-rw-r--r--core/java/android/service/dreams/Sandman.java3
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java31
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java35
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl1
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl2
-rw-r--r--core/java/com/android/internal/app/ToolbarActionBar.java12
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java7
-rw-r--r--core/java/com/android/internal/os/SomeArgs.java10
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java36
-rw-r--r--core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl2
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/layout/common_tab_settings.xml60
-rw-r--r--core/res/res/values-az-rAZ-watch/strings.xml24
-rw-r--r--core/res/res/values-eu-rES/strings.xml2
-rw-r--r--core/res/res/values-mcc310-mnc260-az-rAZ/strings.xml32
-rw-r--r--core/res/res/values-mcc310-mnc260-de/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml4
-rwxr-xr-xcore/res/res/values/symbols.xml1
-rw-r--r--docs/html/distribute/essentials/quality/tv.jd6
-rw-r--r--packages/BackupRestoreConfirmation/res/values-fa/strings.xml2
-rw-r--r--packages/BackupRestoreConfirmation/res/values-hr/strings.xml6
-rw-r--r--packages/BackupRestoreConfirmation/res/values-iw/strings.xml2
-rw-r--r--packages/BackupRestoreConfirmation/res/values-ml-rIN/strings.xml2
-rw-r--r--packages/BackupRestoreConfirmation/res/values-sk/strings.xml2
-rw-r--r--packages/BackupRestoreConfirmation/res/values-sv/strings.xml2
-rw-r--r--packages/DefaultContainerService/AndroidManifest.xml1
-rw-r--r--packages/DefaultContainerService/res/values-fr/strings.xml2
-rw-r--r--packages/DefaultContainerService/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-gu-rIN/strings.xml10
-rw-r--r--packages/DocumentsUI/res/values-ml-rIN/strings.xml4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java9
-rw-r--r--packages/ExternalStorageProvider/res/values-da/strings.xml4
-rw-r--r--packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml4
-rw-r--r--packages/ExternalStorageProvider/res/values-ru/strings.xml2
-rw-r--r--packages/InputDevices/res/values-uk/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-fr/strings.xml2
-rw-r--r--packages/Shell/res/values-bg/strings.xml2
-rw-r--r--packages/Shell/res/values-ca/strings.xml2
-rw-r--r--packages/Shell/res/values-gu-rIN/strings.xml4
-rw-r--r--packages/Shell/res/values-hr/strings.xml2
-rw-r--r--packages/Shell/res/values-pl/strings.xml2
-rw-r--r--packages/Shell/res/values-sk/strings.xml2
-rw-r--r--packages/Shell/src/com/android/shell/BugreportReceiver.java1
-rw-r--r--packages/SystemUI/res/layout/qs_detail_item.xml2
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java2
-rw-r--r--rs/java/android/renderscript/ScriptIntrinsicBLAS.java2
-rw-r--r--services/core/java/com/android/server/DockObserver.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java24
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java7
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java3
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java64
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java2
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java30
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java1
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java52
-rw-r--r--services/core/java/com/android/server/power/Notifier.java20
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java42
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java11
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java11
-rw-r--r--services/usb/java/com/android/server/usb/UsbDebuggingManager.java13
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java25
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java7
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java753
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java274
-rw-r--r--services/usb/java/com/android/server/usb/UsbSettingsManager.java23
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java38
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java25
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java12
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java16
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java181
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfo.java16
-rwxr-xr-xtelephony/java/com/android/internal/telephony/ISub.aidl4
-rw-r--r--tests/VoiceInteraction/res/layout/voice_interaction_session.xml71
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java42
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java8
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java36
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java63
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java8
107 files changed, 2645 insertions, 295 deletions
diff --git a/Android.mk b/Android.mk
index 1de362573d29..121bc8e4b7bb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -668,7 +668,8 @@ dirs_to_check_apis := \
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
dirs_to_document := \
$(dirs_to_check_apis) \
- $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS))
+ $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
+ $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS)) \
# These are relative to frameworks/base
html_dirs := \
diff --git a/api/current.txt b/api/current.txt
index df9ea355bbc0..ea33eaf40fb9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28785,11 +28785,13 @@ package android.service.voice {
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+ method public int getDisabledShowContext();
method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
method public void onLaunchVoiceAssistFromKeyguard();
method public void onReady();
method public void onShutdown();
+ method public void setDisabledShowContext(int);
method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
@@ -28801,6 +28803,7 @@ package android.service.voice {
method public void closeSystemDialogs();
method public void finish();
method public android.content.Context getContext();
+ method public int getDisabledShowContext();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
method public void hide();
@@ -28832,6 +28835,7 @@ package android.service.voice {
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
method public void setContentView(android.view.View);
+ method public void setDisabledShowContext(int);
method public void setKeepAwake(boolean);
method public void setTheme(int);
method public void show(android.os.Bundle, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index eb1c4313ce9a..cbb1bb26dc06 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30934,11 +30934,13 @@ package android.service.voice {
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+ method public int getDisabledShowContext();
method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
method public void onLaunchVoiceAssistFromKeyguard();
method public void onReady();
method public void onShutdown();
+ method public void setDisabledShowContext(int);
method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
@@ -30950,6 +30952,7 @@ package android.service.voice {
method public void closeSystemDialogs();
method public void finish();
method public android.content.Context getContext();
+ method public int getDisabledShowContext();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
method public void hide();
@@ -30981,6 +30984,7 @@ package android.service.voice {
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
method public void setContentView(android.view.View);
+ method public void setDisabledShowContext(int);
method public void setKeepAwake(boolean);
method public void setTheme(int);
method public void show(android.os.Bundle, int);
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index da8586c14256..2754f2d270bd 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -70,7 +70,7 @@ public class PowerCommand extends Svc.Command {
if (val != 0) {
// if the request is not to set it to false, wake up the screen so that
// it can stay on as requested
- pm.wakeUp(SystemClock.uptimeMillis());
+ pm.wakeUp(SystemClock.uptimeMillis(), "PowerCommand", null);
}
pm.setStayOnSetting(val);
}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 4d3434970ae7..72f8c779227a 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1057,6 +1057,11 @@ public abstract class ActionBar {
}
/** @hide */
+ public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /** @hide */
public boolean collapseActionView() {
return false;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d07238aa702b..7572799108a1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2469,7 +2469,9 @@ public class Activity extends ContextThemeWrapper
* @return True if the key shortcut was handled.
*/
public boolean onKeyShortcut(int keyCode, KeyEvent event) {
- return false;
+ // Let the Action Bar have a chance at handling the shortcut.
+ ActionBar actionBar = getActionBar();
+ return (actionBar != null && actionBar.onKeyShortcut(keyCode, event));
}
/**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bf3bfaea11ff..08e1696759cc 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -233,8 +233,10 @@ public class AppOpsManager {
public static final int OP_READ_EXTERNAL_STORAGE = 59;
/** @hide Write external storage. */
public static final int OP_WRITE_EXTERNAL_STORAGE = 60;
+ /** @hide Turned on the screen. */
+ public static final int OP_TURN_SCREEN_ON = 61;
/** @hide */
- public static final int _NUM_OP = 61;
+ public static final int _NUM_OP = 62;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -393,7 +395,8 @@ public class AppOpsManager {
OP_READ_CELL_BROADCASTS,
OP_MOCK_LOCATION,
OP_READ_EXTERNAL_STORAGE,
- OP_WRITE_EXTERNAL_STORAGE
+ OP_WRITE_EXTERNAL_STORAGE,
+ OP_TURN_SCREEN_ON,
};
/**
@@ -461,7 +464,8 @@ public class AppOpsManager {
OPSTR_READ_CELL_BROADCASTS,
OPSTR_MOCK_LOCATION,
OPSTR_READ_EXTERNAL_STORAGE,
- OPSTR_WRITE_EXTERNAL_STORAGE
+ OPSTR_WRITE_EXTERNAL_STORAGE,
+ null,
};
/**
@@ -528,8 +532,9 @@ public class AppOpsManager {
"BODY_SENSORS",
"READ_CELL_BROADCASTS",
"MOCK_LOCATION",
- "OPSTR_READ_EXTERNAL_STORAGE",
- "OPSTR_WRITE_EXTERNAL_STORAGE",
+ "READ_EXTERNAL_STORAGE",
+ "WRITE_EXTERNAL_STORAGE",
+ "TURN_ON_SCREEN",
};
/**
@@ -598,6 +603,7 @@ public class AppOpsManager {
null,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ null, // no permission for turning the screen on
};
/**
@@ -666,7 +672,8 @@ public class AppOpsManager {
null, // READ_CELL_BROADCASTS
null, // MOCK_LOCATION
null, // READ_EXTERNAL_STORAGE
- null // WRITE_EXTERNAL_STORAGE
+ null, // WRITE_EXTERNAL_STORAGE
+ null, // TURN_ON_SCREEN
};
/**
@@ -734,7 +741,8 @@ public class AppOpsManager {
false, // READ_CELL_BROADCASTS
false, // MOCK_LOCATION
false, // READ_EXTERNAL_STORAGE
- false // WRITE_EXTERNAL_STORAGE
+ false, // WRITE_EXTERNAL_STORAGE
+ false, // TURN_ON_SCREEN
};
/**
@@ -765,7 +773,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
- AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
@@ -801,7 +809,8 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION
AppOpsManager.MODE_ALLOWED,
- AppOpsManager.MODE_ALLOWED
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
};
/**
@@ -872,7 +881,8 @@ public class AppOpsManager {
false,
false,
false,
- false
+ false,
+ false,
};
/**
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 9673c98b253b..40126d6f62a9 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -812,7 +812,7 @@ public class AssistStructure implements Parcelable {
* Returns true if assist data has been blocked starting at this node in the hierarchy.
*/
public boolean isAssistBlocked() {
- return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
+ return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
}
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c9f9b565751a..55716621f515 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3094,6 +3094,13 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_HOME = "android.intent.category.HOME";
/**
+ * This is the setup wizard activity, that is the first activity that is displayed
+ * when the user sets up the device for the first time.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_SETUP_WIZARD = "android.intent.category.SETUP_WIZARD";
+ /**
* This activity is a preference panel.
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 0fe112c33e27..80c7b1a220f4 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -19,6 +19,8 @@ package android.hardware.usb;
import android.app.PendingIntent;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -108,4 +110,13 @@ interface IUsbManager
/* Clear public keys installed for secure USB debugging */
void clearUsbDebuggingKeys();
+
+ /* Gets the list of USB ports. */
+ UsbPort[] getPorts();
+
+ /* Gets the status of the specified USB port. */
+ UsbPortStatus getPortStatus(in String portId);
+
+ /* Sets the port's current role. */
+ void setPortRoles(in String portId, int powerRole, int dataRole);
}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f58b9d6dd14e..c88f2133155e 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -17,6 +17,8 @@
package android.hardware.usb;
+import com.android.internal.util.Preconditions;
+
import android.app.PendingIntent;
import android.content.Context;
import android.os.Bundle;
@@ -74,6 +76,22 @@ public class UsbManager {
public static final String ACTION_USB_STATE =
"android.hardware.usb.action.USB_STATE";
+ /**
+ * Broadcast Action: A broadcast for USB port changes.
+ *
+ * This intent is sent when a USB port is added, removed, or changes state.
+ * <ul>
+ * <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort}
+ * for the port.
+ * <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus}
+ * for the port, or null if the port has been removed
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String ACTION_USB_PORT_CHANGED =
+ "android.hardware.usb.action.USB_PORT_CHANGED";
+
/**
* Broadcast Action: A broadcast for USB device attached event.
*
@@ -214,6 +232,23 @@ public class UsbManager {
public static final String USB_FUNCTION_ACCESSORY = "accessory";
/**
+ * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
+ * containing the {@link UsbPort} object for the port.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PORT = "port";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
+ * containing the {@link UsbPortStatus} object for the port, or null if the port
+ * was removed.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PORT_STATUS = "portStatus";
+
+ /**
* Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and
* {@link #ACTION_USB_DEVICE_DETACHED} broadcasts
* containing the {@link UsbDevice} object for the device.
@@ -499,6 +534,77 @@ public class UsbManager {
return false;
}
+ /**
+ * Returns a list of physical USB ports on the device.
+ * <p>
+ * This list is guaranteed to contain all dual-role USB Type C ports but it might
+ * be missing other ports depending on whether the kernel USB drivers have been
+ * updated to publish all of the device's ports through the new "dual_role_usb"
+ * device class (which supports all types of ports despite its name).
+ * </p>
+ *
+ * @return The list of USB ports, or null if none.
+ *
+ * @hide
+ */
+ public UsbPort[] getPorts() {
+ try {
+ return mService.getPorts();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getPorts", e);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the status of the specified USB port.
+ *
+ * @param port The port to query.
+ * @return The status of the specified USB port, or null if unknown.
+ *
+ * @hide
+ */
+ public UsbPortStatus getPortStatus(UsbPort port) {
+ Preconditions.checkNotNull(port, "port must not be null");
+
+ try {
+ return mService.getPortStatus(port.getId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getPortStatus", e);
+ }
+ return null;
+ }
+
+ /**
+ * Sets the desired role combination of the port.
+ * <p>
+ * The supported role combinations depend on what is connected to the port and may be
+ * determined by consulting
+ * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
+ * </p><p>
+ * Note: This function is asynchronous and may fail silently without applying
+ * the requested changes. If this function does cause a status change to occur then
+ * a {@link #ACTION_USB_PORT_CHANGED} broadcast will be sent.
+ * </p>
+ *
+ * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
+ * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
+ * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST}
+ * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+ *
+ * @hide
+ */
+ public void setPortRoles(UsbPort port, int powerRole, int dataRole) {
+ Preconditions.checkNotNull(port, "port must not be null");
+ UsbPort.checkRoles(powerRole, dataRole);
+
+ try {
+ mService.setPortRoles(port.getId(), powerRole, dataRole);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setPortRole", e);
+ }
+ }
+
/** @hide */
public static String addFunction(String functions, String function) {
if ("none".equals(functions)) {
diff --git a/core/java/android/hardware/usb/UsbPort.aidl b/core/java/android/hardware/usb/UsbPort.aidl
new file mode 100644
index 000000000000..b7a79202914e
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbPort.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.usb;
+
+parcelable UsbPort;
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
new file mode 100644
index 000000000000..c9a4e9b6015a
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -0,0 +1,238 @@
+/*
+ * 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 android.hardware.usb;
+
+import com.android.internal.util.Preconditions;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a physical USB port and describes its characteristics.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class UsbPort implements Parcelable {
+ private final String mId;
+ private final int mSupportedModes;
+
+ /**
+ * Mode bit: This USB port can act as a downstream facing port (host).
+ * <p>
+ * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST}
+ * combination of roles (and possibly others as well).
+ * </p>
+ */
+ public static final int MODE_DFP = 1 << 0;
+
+ /**
+ * Mode bit: This USB port can act as an upstream facing port (device).
+ * <p>
+ * Implies that the port supports the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE}
+ * combination of roles (and possibly others as well).
+ * </p>
+ */
+ public static final int MODE_UFP = 1 << 1;
+
+ /**
+ * Mode bit: This USB port can act either as an downstream facing port (host) or as
+ * an upstream facing port (device).
+ * <p>
+ * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST}
+ * combination of roles and the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE}
+ * combination of roles (and possibly others as well).
+ * </p>
+ */
+ public static final int MODE_DUAL = MODE_DFP | MODE_UFP;
+
+ /**
+ * Power role: This USB port can act as a source (provide power).
+ */
+ public static final int POWER_ROLE_SOURCE = 1;
+
+ /**
+ * Power role: This USB port can act as a sink (receive power).
+ */
+ public static final int POWER_ROLE_SINK = 2;
+
+ /**
+ * Data role: This USB port can act as a host (access data services).
+ */
+ public static final int DATA_ROLE_HOST = 1;
+
+ /**
+ * Data role: This USB port can act as a device (offer data services).
+ */
+ public static final int DATA_ROLE_DEVICE = 2;
+
+ private static final int NUM_DATA_ROLES = 3;
+
+ /** @hide */
+ public UsbPort(String id, int supportedModes) {
+ mId = id;
+ mSupportedModes = supportedModes;
+ }
+
+ /**
+ * Gets the unique id of the port.
+ *
+ * @return The unique id of the port; not intended for display.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Gets the supported modes of the port.
+ * <p>
+ * The actual mode of the port may vary depending on what is plugged into it.
+ * </p>
+ *
+ * @return The supported modes: one of {@link #MODE_DFP}, {@link #MODE_UFP}, or
+ * {@link #MODE_DUAL}.
+ */
+ public int getSupportedModes() {
+ return mSupportedModes;
+ }
+
+ /**
+ * Combines one power and one data role together into a unique value with
+ * exactly one bit set. This can be used to efficiently determine whether
+ * a combination of roles is supported by testing whether that bit is present
+ * in a bit-field.
+ *
+ * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
+ * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
+ * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST}
+ * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+ * @hide
+ */
+ public static int combineRolesAsBit(int powerRole, int dataRole) {
+ checkRoles(powerRole, dataRole);
+ final int index = powerRole * NUM_DATA_ROLES + dataRole;
+ return 1 << index;
+ }
+
+ /** @hide */
+ public static String modeToString(int mode) {
+ switch (mode) {
+ case 0:
+ return "none";
+ case MODE_DFP:
+ return "dfp";
+ case MODE_UFP:
+ return "ufp";
+ case MODE_DUAL:
+ return "dual";
+ default:
+ return Integer.toString(mode);
+ }
+ }
+
+ /** @hide */
+ public static String powerRoleToString(int role) {
+ switch (role) {
+ case 0:
+ return "no-power";
+ case POWER_ROLE_SOURCE:
+ return "source";
+ case POWER_ROLE_SINK:
+ return "sink";
+ default:
+ return Integer.toString(role);
+ }
+ }
+
+ /** @hide */
+ public static String dataRoleToString(int role) {
+ switch (role) {
+ case 0:
+ return "no-data";
+ case DATA_ROLE_HOST:
+ return "host";
+ case DATA_ROLE_DEVICE:
+ return "device";
+ default:
+ return Integer.toString(role);
+ }
+ }
+
+ /** @hide */
+ public static String roleCombinationsToString(int combo) {
+ StringBuilder result = new StringBuilder();
+ result.append("[");
+
+ boolean first = true;
+ while (combo != 0) {
+ final int index = Integer.numberOfTrailingZeros(combo);
+ combo &= ~(1 << index);
+ final int powerRole = index / NUM_DATA_ROLES;
+ final int dataRole = index % NUM_DATA_ROLES;
+ if (first) {
+ first = false;
+ } else {
+ result.append(", ");
+ }
+ result.append(powerRoleToString(powerRole));
+ result.append(':');
+ result.append(dataRoleToString(dataRole));
+ }
+
+ result.append("]");
+ return result.toString();
+ }
+
+ /** @hide */
+ public static void checkRoles(int powerRole, int dataRole) {
+ Preconditions.checkArgumentInRange(powerRole, 0, POWER_ROLE_SINK, "powerRole");
+ Preconditions.checkArgumentInRange(dataRole, 0, DATA_ROLE_DEVICE, "dataRole");
+ }
+
+ @Override
+ public String toString() {
+ return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ dest.writeInt(mSupportedModes);
+ }
+
+ public static final Parcelable.Creator<UsbPort> CREATOR =
+ new Parcelable.Creator<UsbPort>() {
+ @Override
+ public UsbPort createFromParcel(Parcel in) {
+ String id = in.readString();
+ int supportedModes = in.readInt();
+ return new UsbPort(id, supportedModes);
+ }
+
+ @Override
+ public UsbPort[] newArray(int size) {
+ return new UsbPort[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/usb/UsbPortStatus.aidl b/core/java/android/hardware/usb/UsbPortStatus.aidl
new file mode 100644
index 000000000000..9a7e46825fe6
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbPortStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.usb;
+
+parcelable UsbPortStatus;
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
new file mode 100644
index 000000000000..5c0e81ad0b27
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -0,0 +1,144 @@
+/*
+ * 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 android.hardware.usb;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the status of a USB port.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class UsbPortStatus implements Parcelable {
+ private final int mCurrentMode;
+ private final int mCurrentPowerRole;
+ private final int mCurrentDataRole;
+ private final int mSupportedRoleCombinations;
+
+ /** @hide */
+ public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
+ int supportedRoleCombinations) {
+ mCurrentMode = currentMode;
+ mCurrentPowerRole = currentPowerRole;
+ mCurrentDataRole = currentDataRole;
+ mSupportedRoleCombinations = supportedRoleCombinations;
+ }
+
+ /**
+ * Returns true if there is anything connected to the port.
+ *
+ * @return True if there is anything connected to the port.
+ */
+ public boolean isConnected() {
+ return mCurrentMode != 0;
+ }
+
+ /**
+ * Gets the current mode of the port.
+ *
+ * @return The current mode: {@link UsbPort#MODE_DFP}, {@link UsbPort#MODE_UFP},
+ * or 0 if nothing is connected.
+ */
+ public int getCurrentMode() {
+ return mCurrentMode;
+ }
+
+ /**
+ * Gets the current power role of the port.
+ *
+ * @return The current power role: {@link UsbPort#POWER_ROLE_SOURCE},
+ * {@link UsbPort#POWER_ROLE_SINK}, or 0 if nothing is connected.
+ */
+ public int getCurrentPowerRole() {
+ return mCurrentPowerRole;
+ }
+
+ /**
+ * Gets the current data role of the port.
+ *
+ * @return The current data role: {@link UsbPort#DATA_ROLE_HOST},
+ * {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if nothing is connected.
+ */
+ public int getCurrentDataRole() {
+ return mCurrentDataRole;
+ }
+
+ /**
+ * Returns true if the specified power and data role combination is supported
+ * given what is currently connected to the port.
+ *
+ * @param powerRole The power role to check: {@link UsbPort#POWER_ROLE_SOURCE}
+ * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
+ * @param dataRole The data role to check: either {@link UsbPort#DATA_ROLE_HOST}
+ * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+ */
+ public boolean isRoleCombinationSupported(int powerRole, int dataRole) {
+ return (mSupportedRoleCombinations &
+ UsbPort.combineRolesAsBit(powerRole, dataRole)) != 0;
+ }
+
+ /** @hide */
+ public int getSupportedRoleCombinations() {
+ return mSupportedRoleCombinations;
+ }
+
+ @Override
+ public String toString() {
+ return "UsbPortStatus{connected=" + isConnected()
+ + ", currentMode=" + UsbPort.modeToString(mCurrentMode)
+ + ", currentPowerRole=" + UsbPort.powerRoleToString(mCurrentPowerRole)
+ + ", currentDataRole=" + UsbPort.dataRoleToString(mCurrentDataRole)
+ + ", supportedRoleCombinations="
+ + UsbPort.roleCombinationsToString(mSupportedRoleCombinations)
+ + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCurrentMode);
+ dest.writeInt(mCurrentPowerRole);
+ dest.writeInt(mCurrentDataRole);
+ dest.writeInt(mSupportedRoleCombinations);
+ }
+
+ public static final Parcelable.Creator<UsbPortStatus> CREATOR =
+ new Parcelable.Creator<UsbPortStatus>() {
+ @Override
+ public UsbPortStatus createFromParcel(Parcel in) {
+ int currentMode = in.readInt();
+ int currentPowerRole = in.readInt();
+ int currentDataRole = in.readInt();
+ int supportedRoleCombinations = in.readInt();
+ return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
+ supportedRoleCombinations);
+ }
+
+ @Override
+ public UsbPortStatus[] newArray(int size) {
+ return new UsbPortStatus[size];
+ }
+ };
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 452e4d582e0b..ecb7f5a200f2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1195,9 +1195,11 @@ public abstract class BatteryStats implements Parcelable {
public static final int EVENT_PACKAGE_ACTIVE = 0x0010;
// Event for a package being on the temporary whitelist.
public static final int EVENT_TEMP_WHITELIST = 0x0011;
+ // Event for the screen waking up.
+ public static final int EVENT_SCREEN_WAKE_UP = 0x0012;
// Number of event types.
- public static final int EVENT_COUNT = 0x0012;
+ public static final int EVENT_COUNT = 0x0013;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -1858,12 +1860,14 @@ public abstract class BatteryStats implements Parcelable {
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
- "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist"
+ "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist",
+ "screenwake",
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
- "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw"
+ "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw",
+ "Esw",
};
/**
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 804d3d031817..0f37ac720bc7 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -37,7 +37,7 @@ interface IPowerManager
boolean isWakeLockLevelSupported(int level);
void userActivity(long time, int event, int flags);
- void wakeUp(long time);
+ void wakeUp(long time, String reason, String opPackageName);
void goToSleep(long time, int reason, int flags);
void nap(long time);
boolean isInteractive();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 6ef1cd02ebf8..9a1a03eb3294 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -658,7 +658,17 @@ public final class PowerManager {
*/
public void wakeUp(long time) {
try {
- mService.wakeUp(time);
+ mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void wakeUp(long time, String reason) {
+ try {
+ mService.wakeUp(time, reason, mContext.getOpPackageName());
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2b75f31384f9..b2cec60c0412 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -860,8 +860,23 @@ public class StorageManager {
final IMountService mountService = IMountService.Stub.asInterface(
ServiceManager.getService("mount"));
try {
- final String packageName = ActivityThread.currentOpPackageName();
+ String packageName = ActivityThread.currentOpPackageName();
+ if (packageName == null) {
+ // Package name can be null if the activity thread is running but the app
+ // hasn't bound yet. In this case we fall back to the first package in the
+ // current UID. This works for runtime permissions as permission state is
+ // per UID and permission realted app ops are updated for all UID packages.
+ String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
+ android.os.Process.myUid());
+ if (packageNames == null || packageNames.length <= 0) {
+ return new StorageVolume[0];
+ }
+ packageName = packageNames[0];
+ }
final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
+ if (uid <= 0) {
+ return new StorageVolume[0];
+ }
return mountService.getVolumeList(uid, packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index 5f5b07953156..eeb340b67e68 100644
--- a/core/java/android/service/dreams/Sandman.java
+++ b/core/java/android/service/dreams/Sandman.java
@@ -92,7 +92,8 @@ public final class Sandman {
// be awake by the time this happens. Otherwise the dream may not start.
PowerManager powerManager =
(PowerManager)context.getSystemService(Context.POWER_SERVICE);
- powerManager.wakeUp(SystemClock.uptimeMillis());
+ powerManager.wakeUp(SystemClock.uptimeMillis(),
+ "android.service.dreams:DREAM");
} else {
Slog.i(TAG, "Activating dream by user request.");
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 549c93e098aa..479c9e2f7c30 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -37,7 +37,6 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Locale;
-
/**
* Top-level service of the current global voice interactor, which is providing
* support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
@@ -154,11 +153,39 @@ public class VoiceInteractionService extends Service {
}
/**
+ * Set contextual options you would always like to have disabled when a session
+ * is shown. The flags may be any combination of
+ * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+ * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+ * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}.
+ */
+ public void setDisabledShowContext(int flags) {
+ try {
+ mSystemService.setDisabledShowContext(flags);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Return the value set by {@link #setDisabledShowContext}.
+ */
+ public int getDisabledShowContext() {
+ try {
+ return mSystemService.getDisabledShowContext();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
+ /**
* Request that the associated {@link android.service.voice.VoiceInteractionSession} be
* shown to the user, starting it if necessary.
* @param args Arbitrary arguments that will be propagated to the session.
* @param flags Indicates additional optional behavior that should be performed. May
- * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST}
+ * be any combination of
+ * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+ * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+ * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
* to request that the system generate and deliver assist data on the current foreground
* app as part of showing the session UI.
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e408b36ea523..95f96e801558 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -650,7 +650,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
public void executeMessage(Message msg) {
- SomeArgs args;
+ SomeArgs args = null;
switch (msg.what) {
case MSG_START_CONFIRMATION:
if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj);
@@ -676,6 +676,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1);
args.arg1 = onGetSupportedCommands((String[]) args.arg1);
+ args.complete();
+ args = null;
break;
case MSG_CANCEL:
if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
@@ -723,6 +725,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
doHide();
break;
}
+ if (args != null) {
+ args.recycle();
+ }
}
@Override
@@ -908,12 +913,38 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
}
/**
+ * Equivalent to {@link VoiceInteractionService#setDisabledShowContext
+ * VoiceInteractionService.setDisabledShowContext(int)}.
+ */
+ public void setDisabledShowContext(int flags) {
+ try {
+ mSystemService.setDisabledShowContext(flags);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Equivalent to {@link VoiceInteractionService#getDisabledShowContext
+ * VoiceInteractionService.getDisabledShowContext}.
+ */
+ public int getDisabledShowContext() {
+ try {
+ return mSystemService.getDisabledShowContext();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
+ /**
* Show the UI for this session. This asks the system to go through the process of showing
* your UI, which will eventually culminate in {@link #onShow}. This is similar to calling
* {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
* @param args Arbitrary arguments that will be propagated {@link #onShow}.
* @param flags Indicates additional optional behavior that should be performed. May
- * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST}
+ * be any combination of
+ * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+ * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+ * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
* to request that the system generate and deliver assist data on the current foreground
* app as part of showing the session UI.
*/
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 6f0cec60bd46..3cddbf6b6a56 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -83,6 +83,7 @@ interface IBatteryStats {
void noteScreenState(int state);
void noteScreenBrightness(int brightness);
void noteUserActivity(int uid, int event);
+ void noteWakeUp(String reason, int reasonUid);
void noteInteractive(boolean interactive);
void noteConnectivityChanged(int type, String extra);
void noteMobileRadioPowerState(int powerState, long timestampNs);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 7f54f505e8d5..73ad98107ae4 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -37,6 +37,8 @@ interface IVoiceInteractionManagerService {
void setKeepAwake(IBinder token, boolean keepAwake);
void closeSystemDialogs(IBinder token);
void finish(IBinder token);
+ void setDisabledShowContext(int flags);
+ int getDisabledShowContext();
/**
* Gets the registered Sound model for keyphrase detection for the current user.
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 2b162af6c7ef..c1b184e12fb9 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -463,6 +463,18 @@ public class ToolbarActionBar extends ActionBar {
return true;
}
+ @Override
+ public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+ Menu menu = mDecorToolbar.getMenu();
+ if (menu != null) {
+ menu.performShortcut(keyCode, event, 0);
+ }
+ // This action bar always returns true for handling keyboard shortcuts.
+ // This will block the window from preparing a temporary panel to handle
+ // keyboard shortcuts.
+ return true;
+ }
+
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
mMenuVisibilityListeners.add(listener);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ae2cbadfe505..60f47d673c18 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3122,6 +3122,13 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteWakeUpLocked(String reason, int reasonUid) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SCREEN_WAKE_UP,
+ reason, reasonUid);
+ }
+
public void noteInteractiveLocked(boolean interactive) {
if (mInteractive != interactive) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index b0d24fd311e5..c05e0d8f1256 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -73,6 +73,16 @@ public final class SomeArgs {
}
}
+ public void complete() {
+ synchronized (this) {
+ if (mWaitState != WAIT_WAITING) {
+ throw new IllegalStateException("Not waiting");
+ }
+ mWaitState = WAIT_FINISHED;
+ notifyAll();
+ }
+ }
+
public void recycle() {
if (mInPool) {
throw new IllegalStateException("Already recycled.");
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index b3f688bbbd04..ca6fe619f528 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -285,7 +285,6 @@ public final class FloatingToolbar {
private final Context mContext;
private final View mParent;
- private final int[] mParentPositionOnScreen = new int[2];
private final PopupWindow mPopupWindow;
private final ViewGroup mContentContainer;
private final int mMarginHorizontal;
@@ -339,7 +338,8 @@ public final class FloatingToolbar {
};
private final Rect mViewPortOnScreen = new Rect();
- private final Point mCoordsOnScreen = new Point();
+ private final Point mCoordsOnWindow = new Point();
+ private final int[] mTmpCoords = new int[2];
private final Rect mTmpRect = new Rect();
private final Region mTouchableRegion = new Region();
@@ -450,13 +450,11 @@ public final class FloatingToolbar {
}
refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
preparePopupContent();
- // We need to specify the offset relative to mParent.
+ // We need to specify the position in window coordinates.
// TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
// specify the popup poision in screen coordinates.
- mParent.getLocationOnScreen(mParentPositionOnScreen);
- final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
- final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
- mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, relativeX, relativeY);
+ mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x,
+ mCoordsOnWindow.y);
setTouchableSurfaceInsetsComputer();
runShowAnimation();
}
@@ -519,13 +517,10 @@ public final class FloatingToolbar {
cancelOverflowAnimations();
refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
preparePopupContent();
- // We need to specify the offset relative to mParent.
+ // We need to specify the position in window coordinates.
// TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
// specify the popup poision in screen coordinates.
- mParent.getLocationOnScreen(mParentPositionOnScreen);
- final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
- final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
- mPopupWindow.update(relativeX, relativeY, getWidth(), getHeight());
+ mPopupWindow.update(mCoordsOnWindow.x, mCoordsOnWindow.y, getWidth(), getHeight());
}
/**
@@ -624,7 +619,22 @@ public final class FloatingToolbar {
mOverflowPanel.setOverflowDirection(mOverflowDirection);
}
- mCoordsOnScreen.set(x, y);
+ // We later specify the location of PopupWindow relative to the attached window.
+ // The idea here is that 1) we can get the location of a View in both window coordinates
+ // and screen coordiantes, where the offset between them should be equal to the window
+ // origin, and 2) we can use an arbitrary for this calculation while calculating the
+ // location of the rootview is supposed to be least expensive.
+ // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid
+ // the following calculation.
+ mParent.getRootView().getLocationOnScreen(mTmpCoords);
+ int rootViewLeftOnScreen = mTmpCoords[0];
+ int rootViewTopOnScreen = mTmpCoords[1];
+ mParent.getRootView().getLocationInWindow(mTmpCoords);
+ int rootViewLeftOnWindow = mTmpCoords[0];
+ int rootViewTopOnWindow = mTmpCoords[1];
+ int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow;
+ int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow;
+ mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen);
}
private int getToolbarHeightWithVerticalMargin() {
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
index 7eb2aef2549f..7294124b4cdc 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
@@ -19,7 +19,7 @@ package com.android.internal.widget;
import android.os.IBinder;
/** {@hide} */
-interface IRemoteViewsAdapterConnection {
+oneway interface IRemoteViewsAdapterConnection {
void onServiceConnected(IBinder service);
void onServiceDisconnected();
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d3117b9e6418..062ae27618fd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -186,6 +186,7 @@
<protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
diff --git a/core/res/res/layout/common_tab_settings.xml b/core/res/res/layout/common_tab_settings.xml
new file mode 100644
index 000000000000..d2a4acc29513
--- /dev/null
+++ b/core/res/res/layout/common_tab_settings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/tabs_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="none"
+ android:fillViewport="true">
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="?android:attr/tabWidgetStyle" />
+
+ </HorizontalScrollView>
+
+ <!-- give an empty content area to make tabhost happy -->
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="0dip"
+ android:layout_height="0dip" />
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:smoothScrollbar="false" />
+
+ </LinearLayout>
+
+</TabHost>
diff --git a/core/res/res/values-az-rAZ-watch/strings.xml b/core/res/res/values-az-rAZ-watch/strings.xml
new file mode 100644
index 000000000000..7e4a7620d794
--- /dev/null
+++ b/core/res/res/values-az-rAZ-watch/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="android_upgrading_apk" msgid="1090732262010398759">"Tətbiq <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+</resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index cc23637eb7d6..960bc563f712 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -355,7 +355,7 @@
<string name="permlab_callPhone" msgid="3925836347681847954">"deitu zuzenean telefono-zenbakietara"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Atzitu IMS dei-zerbitzua"</string>
- <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Zuk ezer egin beharrik gabe deiak egiteko IMS zerbitzua erabiltzea baimentzen dio aplikazioari."</string>
+ <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Zuk ezer egin beharrik gabe deiak egiteko IMS zerbitzua erabiltzea baimentzen die aplikazioei."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonoaren egoera eta identitatea irakurtzea"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Gailuaren telefono-eginbideak atzitzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"eragotzi tableta inaktibo ezartzea"</string>
diff --git a/core/res/res/values-mcc310-mnc260-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc260-az-rAZ/strings.xml
new file mode 100644
index 000000000000..32d21c56fca5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260-az-rAZ/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+** Copyright 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 my 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.
+*/
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="7239039348648848288">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item>
+ </string-array>
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item msgid="483847327467331298">"Operatorla qeydiyyatdan keçin"</item>
+ </string-array>
+ <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Zəngi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260-de/strings.xml b/core/res/res/values-mcc310-mnc260-de/strings.xml
index f357bb65118a..3994bba0c3df 100644
--- a/core/res/res/values-mcc310-mnc260-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-de/strings.xml
@@ -23,10 +23,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="7239039348648848288">"Um über WLAN Anrufe durchführen und Nachrichten senden zu können, bitten Sie zuerst Ihren Mobilfunkanbieter, diesen Dienst einzurichten. Aktivieren Sie WLAN-Anrufe dann erneut über die Einstellungen."</item>
+ <item msgid="7239039348648848288">"Um über WLAN telefonieren und Nachrichten senden zu können, bitten Sie zuerst Ihren Mobilfunkanbieter, diesen Dienst einzurichten. Aktivieren Sie die Option \"Anrufe über WLAN\" dann erneut über die Einstellungen."</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="483847327467331298">"Registrieren Sie sich bei Ihrem Mobilfunkanbieter."</item>
</string-array>
- <string name="wfcSpnFormat" msgid="4982938551498609442">"%s WLAN-Anrufe"</string>
+ <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Anrufe über WLAN"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml
index f24bed092a1d..0a9d58dfc26e 100644
--- a/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml
@@ -23,10 +23,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="7239039348648848288">"ವೈ-ಫೈ ಬಳಸಿಕೊಂಡು ಕರೆ ಮಾಡಲು ಮತ್ತು ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು, ಮೊದಲು ಈ ಸಾಧನವನ್ನು ಹೊಂದಿಸಲು ನಿಮ್ಮ ವಾಹಕವನ್ನು ಕೇಳಿ. ತದನಂತರ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಮತ್ತೆ ವೈ-ಫೈ ಆನ್‌ ಮಾಡಿ."</item>
+ <item msgid="7239039348648848288">"Wi-Fi ಬಳಸಿಕೊಂಡು ಕರೆ ಮಾಡಲು ಮತ್ತು ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು, ಮೊದಲು ಈ ಸಾಧನವನ್ನು ಹೊಂದಿಸಲು ನಿಮ್ಮ ವಾಹಕವನ್ನು ಕೇಳಿ. ತದನಂತರ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಮತ್ತೆ Wi-Fi ಆನ್‌ ಮಾಡಿ."</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="483847327467331298">"ನಿಮ್ಮ ವಾಹಕದಲ್ಲಿ ನೋಂದಾಯಿಸಿಕೊಳ್ಳಿ"</item>
</string-array>
- <string name="wfcSpnFormat" msgid="4982938551498609442">"%s ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
+ <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi ಕರೆ ಮಾಡುವಿಕೆ"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml
index 764b79234810..a94680d128b4 100644
--- a/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml
@@ -23,10 +23,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="7239039348648848288">"Wi-Fi വഴി കോളുകൾ വിളിക്കാനും സന്ദേശങ്ങൾ അയയ്‌ക്കാനും ആദ്യം നിങ്ങളുടെ കാരിയറോട് ഈ സേവനം സജ്ജമാക്കാൻ ആവശ്യപ്പെടുക. ക്രമീകരണത്തിൽ നിന്ന് വീണ്ടും Wi-Fi കോളിംഗ് ഓണാക്കുക."</item>
+ <item msgid="7239039348648848288">"വൈഫൈ വഴി കോളുകൾ വിളിക്കാനും സന്ദേശങ്ങൾ അയയ്‌ക്കാനും ആദ്യം നിങ്ങളുടെ കാരിയറോട് ഈ സേവനം സജ്ജമാക്കാൻ ആവശ്യപ്പെടുക. ക്രമീകരണത്തിൽ നിന്ന് വീണ്ടും വൈഫൈ കോളിംഗ് ഓണാക്കുക."</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="483847327467331298">"നിങ്ങളുടെ കാരിയറിൽ രജിസ്റ്റർ ചെയ്യുക"</item>
</string-array>
- <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi കോളിംഗ്"</string>
+ <string name="wfcSpnFormat" msgid="4982938551498609442">"%s വൈഫൈ കോളിംഗ്"</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d41031cba01b..b3304233ab83 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1360,6 +1360,7 @@
<java-symbol type="layout" name="restrictions_pin_setup" />
<java-symbol type="layout" name="immersive_mode_cling" />
<java-symbol type="layout" name="user_switching_dialog" />
+ <java-symbol type="layout" name="common_tab_settings" />
<java-symbol type="anim" name="slide_in_child_bottom" />
<java-symbol type="anim" name="slide_in_right" />
diff --git a/docs/html/distribute/essentials/quality/tv.jd b/docs/html/distribute/essentials/quality/tv.jd
index 20018c3f35dd..c7f6fcbd0bb7 100644
--- a/docs/html/distribute/essentials/quality/tv.jd
+++ b/docs/html/distribute/essentials/quality/tv.jd
@@ -418,9 +418,9 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
</td>
<td>
<p style="margin-bottom:.5em;">
- If the app continues to play sound after the user has left, the app provides a <em>Now
- Playing</em> card on the home screen recommendation row so users can return to the app to
- control playback.
+ If the app continues to play sound or video after the user has left, the
+ app provides a <em>Now Playing</em> card on the home screen recommendation
+ row so users can return to the app to control playback.
(<a href="{@docRoot}training/tv/playback/now-playing.html">Learn how</a>)
</p>
</td>
diff --git a/packages/BackupRestoreConfirmation/res/values-fa/strings.xml b/packages/BackupRestoreConfirmation/res/values-fa/strings.xml
index 4c16374ab45b..96ef731f5063 100644
--- a/packages/BackupRestoreConfirmation/res/values-fa/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-fa/strings.xml
@@ -19,7 +19,7 @@
<string name="backup_confirm_title" msgid="827563724209303345">"پشتیبان‌گیری کامل"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"بازیابی کامل"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"درخواست پشتیبان گیری کامل از تمام داده‌ها به یک رایانه دسک‌تاپ متصل داده شده است. آیا می‌خواهید این عمل انجام شود؟\n\nاگر شما درخواست تهیهٔ نسخهٔ پشتیبان را نداده‌اید، اجازه‌ ادامه عملیات را ندهید."</string>
- <string name="allow_backup_button_label" msgid="4217228747769644068">"از داده‌های من نسخهٔ پشتیبان تهیه شود"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"پشتیبان‌گیری از داده‌های من"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"نسخهٔ پشتیبان تهیه نشود"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"بازیابی کامل تمام داده‌ها از یک رایانه دسک تاپ متصل درخواست شده است. آیا می‌خواهید این اجازه را بدهید؟\n\nاگر خود شما درخواست بازیابی نداده‌اید، اجازه ادامه این عملیات را ندهید. با این کار همه داده‌هایی که اکنون روی دستگاه است جایگزین می‌شود!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"بازیابی داده‌های من"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hr/strings.xml b/packages/BackupRestoreConfirmation/res/values-hr/strings.xml
index 66037f34098e..cda36cbfda90 100644
--- a/packages/BackupRestoreConfirmation/res/values-hr/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hr/strings.xml
@@ -19,7 +19,7 @@
<string name="backup_confirm_title" msgid="827563724209303345">"Puna sigurnosna kopija"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Potpuno vraćanje"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"Zatražena je potpuna sigurnosna kopija svih podataka na povezano stolno računalo. Želite li to dozvoliti?\n\nAko niste vi zatražili sigurnosnu kopiju, ne dozvolite nastavak te radnje."</string>
- <string name="allow_backup_button_label" msgid="4217228747769644068">"Izradi sigurnosnu kopiju mojih podataka"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Sigurnosno kopiranje"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Ne radi sigurnosnu kopiju"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"Zatraženo je potpuno vraćanje svih podataka s povezanog stolnog računala. Želite li to dozvoliti?\n\nAko niste sami zatražili vraćanje, ne dozvolite nastavak radnje. To će zamijeniti sve podatke koji se trenutačno nalaze na uređaju!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Vrati moje podatke"</string>
@@ -28,8 +28,8 @@
<string name="device_encryption_restore_text" msgid="1570864916855208992">"U nastavku unesite svoju zaporku za enkripciju uređaja."</string>
<string name="device_encryption_backup_text" msgid="5866590762672844664">"U nastavku unesite svoju zaporku enkripcije za uređaj. Ona će se upotrijebiti i za enkripciju te za arhivu sigurnosnih kopija."</string>
<string name="backup_enc_password_text" msgid="4981585714795233099">"Unesite zaporku koju ćete upotrebljavati za kriptiranje podataka potpune sigurnosne kopije. Ako je ostavite praznom, bit će upotrijebljena vaša trenutačna zaporka za sigurnosno kopiranje:"</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ako želite kriptirati podatke potpune sigurnosne kopije, u nastavku unesite zaporku:"</string>
- <string name="backup_enc_password_required" msgid="7889652203371654149">"Budući da vam je uređaj kriptiran, morate kriptirati sigurnosne kopije. Unesite zaporku u nastavku:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ako želite šifrirati podatke potpune sigurnosne kopije, u nastavku unesite zaporku:"</string>
+ <string name="backup_enc_password_required" msgid="7889652203371654149">"Budući da vam je uređaj kriptiran, morate šifrirati sigurnosne kopije. Unesite zaporku u nastavku:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"Ako su podaci za vraćanje kriptirani, unesite zaporku u nastavku:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Započinje stvaranje sigurnosne kopije..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Sigurnosna kopija dovršena"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-iw/strings.xml b/packages/BackupRestoreConfirmation/res/values-iw/strings.xml
index 8c2ffaf1ece8..4c13c73acab8 100644
--- a/packages/BackupRestoreConfirmation/res/values-iw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-iw/strings.xml
@@ -19,7 +19,7 @@
<string name="backup_confirm_title" msgid="827563724209303345">"גיבוי מלא"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"שחזור מלא"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"הוגשה בקשה לגיבוי מלא של כל הנתונים במחשב שולחני מחובר. האם אתה רוצה לאפשר פעולה זו? \n\nאם לא ביקשת את הגיבוי בעצמך, אל תאפשר לפעולה להמשיך."</string>
- <string name="allow_backup_button_label" msgid="4217228747769644068">"גבה את הנתונים שלי"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"גיבוי הנתונים שלי"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"אל תגבה"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"הוגשה בקשה לשחזור מלא של כל הנתונים ממחשב שולחני מחובר. האם אתה רוצה לאפשר פעולה זו? \n \n אם לא ביקשת את השחזור בעצמך, אל תאפשר לפעולה להמשיך. פעולה זו תחליף את כל הנתונים שנמצאים כעת במכשיר!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"שחזר את הנתונים שלי"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-ml-rIN/strings.xml b/packages/BackupRestoreConfirmation/res/values-ml-rIN/strings.xml
index b2b4bcb9718b..5f97afa6e8cd 100644
--- a/packages/BackupRestoreConfirmation/res/values-ml-rIN/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ml-rIN/strings.xml
@@ -19,7 +19,7 @@
<string name="backup_confirm_title" msgid="827563724209303345">"പൂർണ്ണ ബാക്കപ്പ്"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"പൂർണ്ണമായി പുനഃസ്ഥാപിക്കൽ"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"കണക്റ്റുചെയ്‌ത ഡെസ്‌ക്‌ടോപ്പ് കമ്പ്യൂട്ടറിലേക്കുള്ള എല്ലാ ഡാറ്റയുടെയും പൂർണ്ണ ബാക്കപ്പ് ആവശ്യപ്പെട്ടു. ഇത് സംഭവിക്കാൻ അനുവദിക്കണോ?\n\nനിങ്ങൾ സ്വയം ബാക്കപ്പുചെയ്യാൻ ആവശ്യപ്പെട്ടില്ലെങ്കിൽ, ഈ പ്രവർത്തനം തുടരാൻ അനുവദിക്കരുത്."</string>
- <string name="allow_backup_button_label" msgid="4217228747769644068">"എന്റെ ഡാറ്റ ബാക്കപ്പുചെയ്യുക"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"ഡാറ്റ ബാക്കപ്പുചെയ്യൂ"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"ബാക്കപ്പ് ചെയ്യരുത്"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"കണക്റ്റുചെയ്‌ത ഡെസ്‌ക്‌ടോപ്പ് കമ്പ്യൂട്ടറിലേക്കുള്ള എല്ലാ ഡാറ്റയുടെയും പൂർണ്ണ ബാക്കപ്പ് ആവശ്യപ്പെട്ടു. ഇത് സംഭവിക്കാൻ അനുവദിക്കണോ?\n\nനിങ്ങൾ സ്വയം ബാക്കപ്പുചെയ്യാൻ ആവശ്യപ്പെട്ടില്ലെങ്കിൽ, ഈ പ്രവർത്തനം തുടരാൻ അനുവദിക്കരുത്. ഇത് ഉപകരണത്തിൽ നിലവിലുള്ള എല്ലാ ഡാറ്റയേയും മാറ്റി പകരം വയ്ക്കും!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"എന്റെ ഡാറ്റ പുനഃസ്ഥാപിക്കുക"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
index a231d23d0631..804f980b1674 100644
--- a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
@@ -19,7 +19,7 @@
<string name="backup_confirm_title" msgid="827563724209303345">"Úplná záloha"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Úplné obnovenie"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"Bola vyžiadaná úplná záloha všetkých dát do pripojeného počítača. Chcete túto akciu povoliť?\n\nAk ste zálohu nevyžiadali vy, túto operáciu nepovoľujte."</string>
- <string name="allow_backup_button_label" msgid="4217228747769644068">"Zálohovať údaje"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Zálohovať dáta"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Nezálohovať"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?\n\nAk ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Obnoviť údaje"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sv/strings.xml b/packages/BackupRestoreConfirmation/res/values-sv/strings.xml
index 3ae37cf701d4..dee8bc2e88ba 100644
--- a/packages/BackupRestoreConfirmation/res/values-sv/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sv/strings.xml
@@ -19,7 +19,7 @@
<string name="backup_confirm_title" msgid="827563724209303345">"Fullständig säkerhetskopiering"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Fullständig återställning"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"En fullständig säkerhetskopia av alla data till en ansluten dator har begärts. Vill du tillåta detta?\n\nOm du inte själv begärde säkerhetskopian ska du inte tillåta detta."</string>
- <string name="allow_backup_button_label" msgid="4217228747769644068">"Säkerhetskopiera mina data"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Säkerhetskopiera data"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Säkerhetskopiera inte"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"En fullständig återställning av alla data från en ansluten dator har begärts. Vill du tillåta detta? \n \n Om du inte själv har begärt återställningen ska du inte tillåta den. Alla data som finns på enheten kommer då att ersättas!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Återställ mina data"</string>
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 6a72d831b927..e67c5542d40a 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -9,6 +9,7 @@
view storage for all users -->
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<application android:label="@string/service_name"
android:allowBackup="false">
diff --git a/packages/DefaultContainerService/res/values-fr/strings.xml b/packages/DefaultContainerService/res/values-fr/strings.xml
index 5c458bcaddd8..216d715996c7 100644
--- a/packages/DefaultContainerService/res/values-fr/strings.xml
+++ b/packages/DefaultContainerService/res/values-fr/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"Aide accès au package"</string>
+ <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
</resources>
diff --git a/packages/DefaultContainerService/res/values-pt-rPT/strings.xml b/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
index 5c03669c9775..8ea6a3af4e1b 100644
--- a/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
+++ b/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"Ajuda p/ aceder pacotes"</string>
+ <string name="service_name" msgid="4841491635055379553">"Ajuda p/ aceder a pacotes"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index a76c49057864..0281ba94581d 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -31,18 +31,18 @@
<string name="menu_delete" msgid="8138799623850614177">"કાઢી નાખો"</string>
<string name="menu_select_all" msgid="8323579667348729928">"બધા પસંદ કરો"</string>
<string name="menu_copy" msgid="3612326052677229148">"આના પર કૉપિ કરો…"</string>
- <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"આંતરિક સ્ટોરેજ દર્શાવો"</string>
- <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD કાર્ડ દર્શાવો"</string>
+ <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"આંતરિક સ્ટોરેજ બતાવો"</string>
+ <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD કાર્ડ બતાવો"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"આંતરિક સંગ્રહ છુપાવો"</string>
<string name="menu_advanced_hide" product="default" msgid="4845869969015718848">"SD કાર્ડ છુપાવો"</string>
- <string name="menu_file_size_show" msgid="3240323619260823076">"ફાઇલ કદ દર્શાવો"</string>
+ <string name="menu_file_size_show" msgid="3240323619260823076">"ફાઇલ કદ બતાવો"</string>
<string name="menu_file_size_hide" msgid="8881975928502581042">"ફાઇલ કદ છુપાવો"</string>
<string name="button_select" msgid="527196987259139214">"પસંદ કરો"</string>
<string name="button_copy" msgid="8706475544635021302">"કૉપિ કરો"</string>
<string name="sort_name" msgid="9183560467917256779">"નામ દ્વારા"</string>
<string name="sort_date" msgid="586080032956151448">"સંશોધન તારીખ દ્વારા"</string>
<string name="sort_size" msgid="3350681319735474741">"કદ દ્વારા"</string>
- <string name="drawer_open" msgid="4545466532430226949">"રૂટ્સ દર્શાવો"</string>
+ <string name="drawer_open" msgid="4545466532430226949">"રૂટ્સ બતાવો"</string>
<string name="drawer_close" msgid="7602734368552123318">"રૂટ્સ છુપાવો"</string>
<string name="save_error" msgid="6167009778003223664">"દસ્તાવેજ સાચવવામાં નિષ્ફળ થયાં."</string>
<string name="create_error" msgid="3735649141335444215">"ફોલ્ડર બનાવવામાં નિષ્ફળ થયા"</string>
@@ -52,7 +52,7 @@
<string name="root_type_service" msgid="2178854894416775409">"સંગ્રહ સેવાઓ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"શોર્ટકટ્સ"</string>
<string name="root_type_device" msgid="7121342474653483538">"ઉપકરણો"</string>
- <string name="root_type_apps" msgid="8838065367985945189">"વધુ એપ્લિકેશન્સ"</string>
+ <string name="root_type_apps" msgid="8838065367985945189">"વધુ એપ્લિકેશનો"</string>
<string name="empty" msgid="7858882803708117596">"કોઈ આઇટમ્સ નથી"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ફાઇલ ખોલી શકાતી નથી"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"કેટલાક દસ્તાવેજો કાઢી નાખવામાં અસમર્થ"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 56b22b1645aa..4c4b4819312e 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -31,9 +31,9 @@
<string name="menu_delete" msgid="8138799623850614177">"ഇല്ലാതാക്കുക"</string>
<string name="menu_select_all" msgid="8323579667348729928">"എല്ലാം തിരഞ്ഞെടുക്കുക"</string>
<string name="menu_copy" msgid="3612326052677229148">"ഇതിൽ പകർത്തുക…"</string>
- <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ആന്തരിക സംഭരണം കാണിക്കുക"</string>
+ <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ആന്തരിക സ്റ്റോറേജ് കാണിക്കുക"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD കാർഡ് കാണിക്കുക"</string>
- <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ആന്തരിക സംഭരണം മറയ്‌ക്കുക"</string>
+ <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ആന്തരിക സ്റ്റോറേജ് മറയ്‌ക്കുക"</string>
<string name="menu_advanced_hide" product="default" msgid="4845869969015718848">"SD കാർഡ് മറയ്‌ക്കുക"</string>
<string name="menu_file_size_show" msgid="3240323619260823076">"ഫയൽ വലുപ്പം കാണിക്കുക"</string>
<string name="menu_file_size_hide" msgid="8881975928502581042">"ഫയൽ വലുപ്പം മറയ്‌ക്കുക"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index c541bca9c398..a57bcc6f2269 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -720,14 +720,15 @@ public class DocumentsActivity extends BaseActivity {
if (mState.action == ACTION_GET_CONTENT) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- } else if (mState.action == ACTION_OPEN_TREE ||
- mState.action == ACTION_OPEN_COPY_DESTINATION) {
+ } else if (mState.action == ACTION_OPEN_TREE) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- // TODO: Move passing the stack to the separate ACTION_COPY action once it's implemented.
- intent.putExtra(CopyService.EXTRA_STACK, (Parcelable)mState.stack);
+ } else if (mState.action == ACTION_OPEN_COPY_DESTINATION) {
+ // Picking a copy destination is only used internally by us, so we
+ // don't need to extend permissions to the caller.
+ intent.putExtra(CopyService.EXTRA_STACK, (Parcelable) mState.stack);
} else {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
diff --git a/packages/ExternalStorageProvider/res/values-da/strings.xml b/packages/ExternalStorageProvider/res/values-da/strings.xml
index a9ecb691d727..dc565aeca851 100644
--- a/packages/ExternalStorageProvider/res/values-da/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-da/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <string name="app_label" msgid="7123375275748530234">"Ekstern lagerplads"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Intern lagerplads"</string>
<string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
index 204b336bd30d..08e6dae52b53 100644
--- a/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="7123375275748530234">"ബാഹ്യ സംഭരണം"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"ആന്തരിക സംഭരണം"</string>
+ <string name="app_label" msgid="7123375275748530234">"ബാഹ്യ സ്റ്റോറേജ്"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"ആന്തരിക സ്റ്റോറേജ്"</string>
<string name="root_documents" msgid="4051252304075469250">"പ്രമാണങ്ങൾ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ru/strings.xml b/packages/ExternalStorageProvider/res/values-ru/strings.xml
index b6c109513bb0..740272f7b5cd 100644
--- a/packages/ExternalStorageProvider/res/values-ru/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ru/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Внешний накопитель"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Внутренняя память"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Внутренний накопитель"</string>
<string name="root_documents" msgid="4051252304075469250">"Документы"</string>
</resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index d8152d40723c..43a3fe63766d 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -3,7 +3,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="8016145283189546017">"Пристрої вводу"</string>
<string name="keyboard_layouts_label" msgid="6688773268302087545">"Клавіатура Android"</string>
- <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"англійська (Великобританія)"</string>
+ <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"англійська (Велика Британія)"</string>
<string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"англійська (США)"</string>
<string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"англійська (США), міжнародна"</string>
<string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"англійська (США), розкладка Colemak"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 5f3d5b6c79ac..1f5c71680c5f 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -34,7 +34,7 @@
<string name="install_for_print_preview" msgid="6366303997385509332">"Installer un lecteur PDF pour afficher l\'aperçu"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"L\'application à l\'origine de l\'impression a planté"</string>
<string name="generating_print_job" msgid="3119608742651698916">"Génération tâche impression…"</string>
- <string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer au format .PDF"</string>
+ <string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer au format PDF"</string>
<string name="all_printers" msgid="5018829726861876202">"Toutes les imprim."</string>
<string name="print_dialog" msgid="32628687461331979">"Boîte de dialogue d\'impression"</string>
<string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index 2d779b6bea39..381d5d8514d3 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -22,5 +22,5 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Докоснете, за да споделите отчета си за програмни грешки"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчетите за програмни грешки съдържат данни от различни регистрационни файлове на системата, включително лична и поверителна информация. Споделяйте ги само с приложения и хора, на които имате доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Това съобщение да се показва следващия път"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Отчети за програмни грешки"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Отчети за прогр. грешки"</string>
</resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 327fdc23bc5c..b07bafd37778 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Protecció"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"S\'ha registrat l\'informe d\'error"</string>
- <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Fes lliscar el dit cap a l\'esquerra per compartir l\'informe d\'errors."</string>
+ <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Llisca cap a l\'esquerra per compartir l\'informe d\'errors."</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Els informes d\'error contenen dades dels diferents fitxers de registre del sistema, inclosa informació privada i personal. Comparteix els informes d\'error només amb les aplicacions i amb les persones en qui confies."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra aquest missatge la propera vegada"</string>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 53e385235ff3..e9fdfdbe27e9 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -20,7 +20,7 @@
<string name="bugreport_finished_title" msgid="2293711546892863898">"બગ રિપોર્ટ કેપ્ચર કરી"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"તમારી બગ રિપોર્ટ શેર કરવા માટે ડાબે સ્વાઇપ કરો"</string>
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"તમારી બગ રિપોર્ટ શેર કરવા માટે ટચ કરો"</string>
- <string name="bugreport_confirm" msgid="5130698467795669780">"બગ રિપોર્ટ્સ વ્યક્તિગત અને ખાનગી માહિતી સહિત, સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે. બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે એપ્લિકેશન્સ અને લોકો સાથે જ શેર કરો."</string>
- <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"આગલી વખતે આ સંદેશ દર્શાવો"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"બગ રિપોર્ટ્સ વ્યક્તિગત અને ખાનગી માહિતી સહિત, સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે. બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે એપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"આગલી વખતે આ સંદેશ બતાવો"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ્સ"</string>
</resources>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index cf122abcacb1..a2cb3b0d0327 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -22,5 +22,5 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Prijave programskih pogrešaka sadržavaju podatke iz različitih datoteka zapisnika sustava, uključujući osobne i privatne informacije. Prijave programskih pogrešaka dijelite samo s aplikacijama i osobama koje smatrate pouzdanima."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži tu poruku sljedeći put"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvješća o programskim pogreškama"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
</resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 266f070a8d7e..96b8f2ac8cd3 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -22,5 +22,5 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Raporty o błędach zawierają dane z różnych plików dzienników systemu, w tym dane osobowe i prywatne. Udostępniaj je tylko aplikacjom i osobom, którym ufasz."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaż ten komunikat następnym razem"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Zgłoszenia błędów"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Raporty o błędach"</string>
</resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index a79059dead87..4228dd3d1ce2 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -22,5 +22,5 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia o chybe"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
</resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index 6278650775f5..d83b516fade2 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -215,6 +215,7 @@ public class BugreportReceiver extends BroadcastReceiver {
ZipOutputStream zos = new ZipOutputStream(
new BufferedOutputStream(new FileOutputStream(bugreportZippedFile)))) {
ZipEntry entry = new ZipEntry(bugreportFile.getName());
+ entry.setTime(bugreportFile.lastModified());
zos.putNextEntry(entry);
int totalBytes = Streams.copy(is, zos);
Log.v(TAG, "size of original bugreport: " + totalBytes + " bytes");
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index a519d3f8b3dd..6facb715640d 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -20,6 +20,7 @@
android:minHeight="@dimen/qs_detail_item_height"
android:background="@drawable/btn_borderless_rect"
android:clickable="true"
+ android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal" >
@@ -57,6 +58,7 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:clickable="true"
+ android:focusable="true"
android:scaleType="center"
android:src="@drawable/ic_qs_cancel" />
diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
index 6a000fd66022..dc7577af29ee 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
@@ -27,6 +27,7 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end"
+ android:focusable="true"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/accessibility_clear_all"/>
</com.android.systemui.statusbar.DismissView>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 155f5ea2d536..3210a24e536f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -583,7 +583,7 @@
<dimen name="managed_profile_toast_padding">4dp</dimen>
<!-- Thickness of the assist disclosure beams -->
- <dimen name="assist_disclosure_thickness">3dp</dimen>
+ <dimen name="assist_disclosure_thickness">2.5dp</dimen>
<!-- Thickness of the shadows of the assist disclosure beams -->
<dimen name="assist_disclosure_shadow_thickness">1.5dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 6d2c8c09dfaf..1a26a4dad39e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -78,8 +78,7 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
return;
}
state.value = rotationLocked;
- final boolean portrait = mContext.getResources().getConfiguration().orientation
- != Configuration.ORIENTATION_LANDSCAPE;
+ final boolean portrait = isCurrentOrientationLockPortrait();
final AnimationIcon icon;
if (rotationLocked) {
final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
@@ -98,6 +97,17 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
R.string.accessibility_rotation_lock_off);
}
+ private boolean isCurrentOrientationLockPortrait() {
+ int lockOrientation = mController.getRotationLockOrientation();
+ if (lockOrientation == Configuration.ORIENTATION_UNDEFINED) {
+ // Freely rotating device; use current rotation
+ return mContext.getResources().getConfiguration().orientation
+ != Configuration.ORIENTATION_LANDSCAPE;
+ } else {
+ return lockOrientation != Configuration.ORIENTATION_LANDSCAPE;
+ }
+ }
+
@Override
public int getMetricsCategory() {
return MetricsLogger.QS_ROTATIONLOCK;
@@ -116,9 +126,7 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
int idWhenOff) {
int stringID;
if (locked) {
- final boolean portrait = mContext.getResources().getConfiguration().orientation
- != Configuration.ORIENTATION_LANDSCAPE;
- stringID = portrait ? idWhenPortrait: idWhenLandscape;
+ stringID = isCurrentOrientationLockPortrait() ? idWhenPortrait: idWhenLandscape;
} else {
stringID = idWhenOff;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index da1f03ee2b45..f7c3c670ac4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -478,7 +478,6 @@ public class SignalClusterView
}
private void setTint(ImageView v, int tint) {
- v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
v.setImageTintList(ColorStateList.valueOf(tint));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 88aa071c0ab3..1e78f66e6ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3907,7 +3907,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void wakeUpIfDozing(long time, MotionEvent event) {
if (mDozing && mDozeScrimController.isPulsing()) {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- pm.wakeUp(time);
+ pm.wakeUp(time, "com.android.systemui:NODOZE");
mScreenOnComingFromTouch = true;
mScreenOnTouchLocation = new PointF(event.getX(), event.getY());
mNotificationPanel.setTouchDisabled(false);
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
index 06134e5acb51..c04191bb095d 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
@@ -3272,7 +3272,7 @@ public final class ScriptIntrinsicBLAS extends ScriptIntrinsic {
/**
- * 8-bit GEMM-like operation for neural networks: C = B.transposed() * A
+ * 8-bit GEMM-like operation for neural networks: C = A * Transpose(B)
* Calculations are done in 1.10.21 fixed-point format for the final output,
* just before there's a shift down to drop the fractional parts. The output
* values are gated to 0 to 255 to fit in a byte, but the 10-bit format
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index 41ce25d38078..5388f107c7e7 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -134,7 +134,8 @@ final class DockObserver extends SystemService {
if (mAllowTheaterModeWakeFromDock
|| Settings.Global.getInt(getContext().getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0) == 0) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+ "android.server:DOCK");
}
updateLocked();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37aa40847ff1..1582037ad4b0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10801,6 +10801,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// We are now ready to launch the assist activity.
+ IResultReceiver sendReceiver = null;
+ Bundle sendBundle = null;
synchronized (this) {
buildAssistBundleLocked(pae, extras);
boolean exists = mPendingAssistExtras.remove(pae);
@@ -10809,19 +10811,21 @@ public final class ActivityManagerService extends ActivityManagerNative
// Timed out.
return;
}
- if (pae.receiver != null) {
+ if ((sendReceiver=pae.receiver) != null) {
// Caller wants result sent back to them.
- Bundle topBundle = new Bundle();
- topBundle.putBundle("data", pae.extras);
- topBundle.putParcelable("structure", pae.structure);
- topBundle.putParcelable("content", pae.content);
- try {
- pae.receiver.send(0, topBundle);
- } catch (RemoteException e) {
- }
- return;
+ sendBundle = new Bundle();
+ sendBundle.putBundle("data", pae.extras);
+ sendBundle.putParcelable("structure", pae.structure);
+ sendBundle.putParcelable("content", pae.content);
}
}
+ if (sendReceiver != null) {
+ try {
+ sendReceiver.send(0, sendBundle);
+ } catch (RemoteException e) {
+ }
+ return;
+ }
long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 13b75abcf0f5..4b0b924e2ddb 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -493,6 +493,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ public void noteWakeUp(String reason, int reasonUid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWakeUpLocked(reason, reasonUid);
+ }
+ }
+
public void noteInteractive(boolean interactive) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 458928f6e75b..8813a61fc5fb 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -648,7 +648,8 @@ public final class DreamManagerService extends SystemService {
if (mCurrentDreamName != null && mCurrentDreamCanDoze
&& !mCurrentDreamName.equals(getDozeComponent())) {
// May have updated the doze component, wake up
- mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+ "android.server.dreams:SYSPROP");
}
}
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 4d8d10568f0a..8871e646d917 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -86,6 +86,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
Handler mHandler = new Handler() {
+ @Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_USER_SWITCHING:
@@ -274,7 +275,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
Slog.w(TAG, "enroll: no fingeprintd!");
return;
}
- stopPendingOperations();
+ stopPendingOperations(true);
mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
@@ -315,17 +316,23 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return 0;
}
- private void stopPendingOperations() {
+ private void stopPendingOperations(boolean initiatedByClient) {
if (mEnrollClient != null) {
- stopEnrollment(mEnrollClient.token, true);
+ stopEnrollment(mEnrollClient.token, initiatedByClient);
}
if (mAuthClient != null) {
- stopAuthentication(mAuthClient.token, true);
+ stopAuthentication(mAuthClient.token, initiatedByClient);
}
// mRemoveClient is allowed to continue
}
- void stopEnrollment(IBinder token, boolean notify) {
+ /**
+ * Stop enrollment in progress and inform client if they initiated it.
+ *
+ * @param token token for client
+ * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+ */
+ void stopEnrollment(IBinder token, boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopEnrollment: no fingeprintd!");
@@ -333,15 +340,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
final ClientMonitor client = mEnrollClient;
if (client == null || client.token != token) return;
- try {
- int result = daemon.cancelEnrollment();
- if (result != 0) {
- Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+ if (initiatedByClient) {
+ try {
+ int result = daemon.cancelEnrollment();
+ if (result != 0) {
+ Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stopEnrollment failed", e);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "stopEnrollment failed", e);
- }
- if (notify) {
client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
}
removeClient(mEnrollClient);
@@ -354,7 +361,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
Slog.w(TAG, "startAuthentication: no fingeprintd!");
return;
}
- stopPendingOperations();
+ stopPendingOperations(true);
mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
@@ -374,7 +381,13 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
}
- void stopAuthentication(IBinder token, boolean notify) {
+ /**
+ * Stop authentication in progress and inform client if they initiated it.
+ *
+ * @param token token for client
+ * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+ */
+ void stopAuthentication(IBinder token, boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopAuthentication: no fingeprintd!");
@@ -382,15 +395,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
final ClientMonitor client = mAuthClient;
if (client == null || client.token != token) return;
- try {
- int result = daemon.cancelAuthentication();
- if (result != 0) {
- Slog.w(TAG, "stopAuthentication failed, result=" + result);
+ if (initiatedByClient) {
+ try {
+ int result = daemon.cancelAuthentication();
+ if (result != 0) {
+ Slog.w(TAG, "stopAuthentication failed, result=" + result);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stopAuthentication failed", e);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "stopAuthentication failed", e);
- }
- if (notify) {
client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
}
removeClient(mAuthClient);
@@ -486,12 +499,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
receiver = null;
}
+ @Override
public void binderDied() {
token = null;
removeClient(this);
receiver = null;
}
+ @Override
protected void finalize() throws Throwable {
try {
if (token != null) {
@@ -565,7 +580,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
// For fingerprint devices that support touch-to-wake, this will ensure the device
// wakes up and turns the screen on when fingerprint is authenticated.
if (mIsKeyguard && authenticated) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+ "android.server.fingerprint:AUTH");
}
return result;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c37f619fca37..cfc5f7d990d8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1969,7 +1969,7 @@ public final class HdmiControlService extends SystemService {
void wakeUp() {
assertRunOnServiceThread();
mWakeUpMessageReceived = true;
- mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE");
// PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets
// the intent, the sequence will continue at onWakeUp().
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index e3c6037fa9ab..7fde68f55b76 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -29,7 +29,6 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
-import android.os.Debug;
import android.os.UserHandle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
@@ -120,12 +119,7 @@ final class DefaultPermissionGrantPolicy {
private static final Set<String> ACCOUNTS_PERMISSIONS = new ArraySet<>();
static {
- //ACCOUNTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
- }
-
- private static final Set<String> SETTINGS_PERMISSIONS = new ArraySet<>();
- static {
- SETTINGS_PERMISSIONS.add(Manifest.permission.WRITE_SETTINGS);
+ ACCOUNTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
}
private final PackageManagerService mService;
@@ -161,7 +155,7 @@ final class DefaultPermissionGrantPolicy {
mDialerAppPackagesProvider = provider;
}
- public void setSyncAdapterPackagesProviderrLPw(SyncAdapterPackagesProvider provider) {
+ public void setSyncAdapterPackagesProviderLPw(SyncAdapterPackagesProvider provider) {
mSyncAdapterPackagesProvider = provider;
}
@@ -256,7 +250,7 @@ final class DefaultPermissionGrantPolicy {
// SetupWizard
Intent setupIntent = new Intent(Intent.ACTION_MAIN);
- setupIntent.addCategory(Intent.CATEGORY_HOME);
+ setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
PackageParser.Package setupPackage = getDefaultSystemHandlerActivityPackageLPr(
setupIntent, userId);
if (setupPackage != null
@@ -374,8 +368,7 @@ final class DefaultPermissionGrantPolicy {
// Calendar provider sync adapters
List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackagesLPr(
- calendarSyncAdapterPackages,
- userId);
+ calendarSyncAdapterPackages, userId);
final int calendarSyncAdapterCount = calendarSyncAdapters.size();
for (int i = 0; i < calendarSyncAdapterCount; i++) {
PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i);
@@ -398,8 +391,7 @@ final class DefaultPermissionGrantPolicy {
// Contacts provider sync adapters
List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackagesLPr(
- contactsSyncAdapterPackages,
- userId);
+ contactsSyncAdapterPackages, userId);
final int contactsSyncAdapterCount = contactsSyncAdapters.size();
for (int i = 0; i < contactsSyncAdapterCount; i++) {
PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i);
@@ -628,10 +620,12 @@ final class DefaultPermissionGrantPolicy {
List<ResolveInfo> handlers = mService.mActivities.queryIntent(intent,
intent.resolveType(mService.mContext.getContentResolver()),
PackageManager.GET_DISABLED_COMPONENTS, userId);
+ if (handlers == null) {
+ return null;
+ }
final int handlerCount = handlers.size();
for (int i = 0; i < handlerCount; i++) {
ResolveInfo handler = handlers.get(i);
- // TODO: This is a temporary hack to figure out the setup app.
PackageParser.Package handlerPackage = getSystemPackageLPr(
handler.activityInfo.packageName);
if (handlerPackage != null) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ef9bc8baa9ae..2a08c340bb3a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -801,12 +801,9 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private static boolean hasValidDomains(ActivityIntentInfo filter) {
- boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
- filter.hasDataScheme(IntentFilter.SCHEME_HTTPS);
- if (!hasHTTPorHTTPS) {
- return false;
- }
- return true;
+ return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
+ && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+ filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
}
private IntentFilterVerifier mIntentFilterVerifier;
@@ -4420,9 +4417,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized(mPackages) {
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
intent, resolvedType, 0, sourceUserId, parent.id);
- return xpDomainInfo != null
- && xpDomainInfo.bestDomainVerificationStatus !=
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+ return xpDomainInfo != null;
}
}
return false;
@@ -4579,6 +4574,11 @@ public class PackageManagerService extends IPackageManager.Stub {
result.bestDomainVerificationStatus);
}
}
+ // Don't consider matches with status NEVER across profiles.
+ if (result != null && result.bestDomainVerificationStatus
+ == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+ return null;
+ }
return result;
}
@@ -4716,8 +4716,7 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
// Browser/generic handling case. If there's a default browser, go straight
// to that (but only if there is no other higher-priority match).
- final String defaultBrowserPackageName = getDefaultBrowserPackageName(
- UserHandle.myUserId());
+ final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
int maxMatchPrio = 0;
ResolveInfo defaultBrowserMatch = null;
final int numCandidates = matchAllList.size();
@@ -9929,7 +9928,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (packageName != null) {
result |= updateIntentVerificationStatus(packageName,
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
- UserHandle.myUserId());
+ userId);
mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
packageName, userId);
}
@@ -15076,8 +15075,9 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (filters != null && filters.size() > 0) {
for (IntentFilter filter : filters) {
- if (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
- filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+ if (filter.hasCategory(Intent.CATEGORY_BROWSABLE)
+ && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+ filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
result.addAll(filter.getHostsList());
}
}
@@ -16407,7 +16407,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setSyncAdapterPackagesProviderrLPw(provider);
+ mDefaultPermissionPolicy.setSyncAdapterPackagesProviderLPw(provider);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 4faf75a3deab..bbdfe31828dd 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -238,6 +238,7 @@ abstract class PackageSettingBase extends SettingBase {
installStatus = base.installStatus;
keySetData = base.keySetData;
verificationInfo = base.verificationInfo;
+ installerPackageName = base.installerPackageName;
}
private PackageUserState modifyUserState(int userId) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9e41f70a8326..13e075cc5c8e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -126,6 +126,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -753,7 +754,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
synchronized (mLock) {
if (shouldEnableWakeGestureLp()) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
- wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture);
+ wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
+ "android.policy:GESTURE");
}
}
}
@@ -1874,21 +1876,33 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (permission != null) {
if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) {
final int callingUid = Binder.getCallingUid();
- // check if this is a system uid first before bothering with
- // obtaining package name
+ // system processes will be automatically allowed privilege to draw
if (callingUid == Process.SYSTEM_UID) {
return WindowManagerGlobal.ADD_OKAY;
}
+ // check if user has enabled this operation. SecurityException will be thrown if
+ // this app has not been allowed by the user
final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid,
attrs.packageName);
- if (mode == AppOpsManager.MODE_DEFAULT) {
- if (mContext.checkCallingPermission(permission) !=
- PackageManager.PERMISSION_GRANTED) {
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ case AppOpsManager.MODE_IGNORED:
+ // although we return ADD_OKAY for MODE_IGNORED, the added window will
+ // actually be hidden in WindowManagerService
+ return WindowManagerGlobal.ADD_OKAY;
+ case AppOpsManager.MODE_ERRORED:
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
- }
+ default:
+ // in the default mode, we will make a decision here based on
+ // checkCallingPermission()
+ if (mContext.checkCallingPermission(permission) !=
+ PackageManager.PERMISSION_GRANTED) {
+ return WindowManagerGlobal.ADD_PERMISSION_DENIED;
+ } else {
+ return WindowManagerGlobal.ADD_OKAY;
+ }
}
- return WindowManagerGlobal.ADD_OKAY;
}
if (mContext.checkCallingOrSelfPermission(permission)
@@ -4691,7 +4705,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
updateRotation(true);
if (lidOpen) {
- wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch);
+ wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch,
+ "android.policy:LID");
} else if (!mLidControlsSleep) {
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
@@ -4713,7 +4728,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
}
- wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens);
+ wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens,
+ "android.policy:CAMERA_COVER");
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
mCameraLensCoverState = lensCoverState;
@@ -4892,7 +4908,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
if (isWakeKey) {
- wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
+ wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
@@ -5123,7 +5139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (isWakeKey) {
- wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
+ wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
@@ -5184,7 +5200,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
if ((policyFlags & FLAG_WAKE) != 0) {
- if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion)) {
+ if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
+ "android.policy:MOTION")) {
return 0;
}
}
@@ -5197,7 +5214,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// there will be no dream to intercept the touch and wake into ambient. The device should
// wake up in this case.
if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
- wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming);
+ wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming,
+ "android.policy:MOTION");
}
return 0;
@@ -5493,10 +5511,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void wakeUpFromPowerKey(long eventTime) {
- wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
+ wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");
}
- private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
+ private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {
final boolean theaterModeEnabled = isTheaterModeEnabled();
if (!wakeInTheaterMode && theaterModeEnabled) {
return false;
@@ -5507,7 +5525,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Global.THEATER_MODE_ON, 0);
}
- mPowerManager.wakeUp(wakeTime);
+ mPowerManager.wakeUp(wakeTime, reason);
return true;
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index d21c6d200dda..c5ad7fed047d 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -472,6 +472,26 @@ final class Notifier {
}
/**
+ * Called when the screen has turned on.
+ */
+ public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) {
+ if (DEBUG) {
+ Slog.d(TAG, "onWakeUp: event=" + reason + ", reasonUid=" + reasonUid
+ + " opPackageName=" + opPackageName + " opUid=" + opUid);
+ }
+
+ try {
+ mBatteryStats.noteWakeUp(reason, reasonUid);
+ if (opPackageName != null) {
+ mAppOps.noteOperation(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+
+ }
+
+ /**
* Called when wireless charging has started so as to provide user feedback.
*/
public void onWirelessChargingStarted() {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3f5975561640..88476cee65c1 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -830,7 +830,18 @@ public final class PowerManagerService extends SystemService
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
&& isScreenLock(wakeLock)) {
- wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), uid);
+ String opPackageName;
+ int opUid;
+ if (wakeLock.mWorkSource != null && wakeLock.mWorkSource.getName(0) != null) {
+ opPackageName = wakeLock.mWorkSource.getName(0);
+ opUid = wakeLock.mWorkSource.get(0);
+ } else {
+ opPackageName = wakeLock.mPackageName;
+ opUid = wakeLock.mWorkSource != null ? wakeLock.mWorkSource.get(0)
+ : wakeLock.mOwnerUid;
+ }
+ wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
+ opPackageName, opUid);
}
}
@@ -1042,17 +1053,19 @@ public final class PowerManagerService extends SystemService
return false;
}
- private void wakeUpInternal(long eventTime, int uid) {
+ private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
+ int opUid) {
synchronized (mLock) {
- if (wakeUpNoUpdateLocked(eventTime, uid)) {
+ if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
- private boolean wakeUpNoUpdateLocked(long eventTime, int uid) {
+ private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
+ String opPackageName, int opUid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
+ Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
}
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
@@ -1064,21 +1077,22 @@ public final class PowerManagerService extends SystemService
try {
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
- Slog.i(TAG, "Waking up from sleep (uid " + uid +")...");
+ Slog.i(TAG, "Waking up from sleep (uid " + reasonUid +")...");
break;
case WAKEFULNESS_DREAMING:
- Slog.i(TAG, "Waking up from dream (uid " + uid +")...");
+ Slog.i(TAG, "Waking up from dream (uid " + reasonUid +")...");
break;
case WAKEFULNESS_DOZING:
- Slog.i(TAG, "Waking up from dozing (uid " + uid +")...");
+ Slog.i(TAG, "Waking up from dozing (uid " + reasonUid +")...");
break;
}
mLastWakeTime = eventTime;
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
+ mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
userActivityNoUpdateLocked(
- eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -1334,7 +1348,8 @@ public final class PowerManagerService extends SystemService
final long now = SystemClock.uptimeMillis();
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) {
- wakeUpNoUpdateLocked(now, Process.SYSTEM_UID);
+ wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
+ mContext.getOpPackageName(), Process.SYSTEM_UID);
}
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
@@ -1788,7 +1803,8 @@ public final class PowerManagerService extends SystemService
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
} else {
- wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
+ wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",
+ Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);
updatePowerStateLocked();
}
} else if (wakefulness == WAKEFULNESS_DOZING) {
@@ -3136,7 +3152,7 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
- public void wakeUp(long eventTime) {
+ public void wakeUp(long eventTime, String reason, String opPackageName) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
@@ -3147,7 +3163,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- wakeUpInternal(eventTime, uid);
+ wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec566bc882ac..bc63c69c4184 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2543,8 +2543,10 @@ public class WindowManagerService extends IWindowManager.Stub
win.attach();
mWindowMap.put(client.asBinder(), win);
if (win.mAppOp != AppOpsManager.OP_NONE) {
- if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
- != AppOpsManager.MODE_ALLOWED) {
+ int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
+ win.getOwningPackage());
+ if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
+ (startOpResult != AppOpsManager.MODE_DEFAULT)) {
win.setAppOpVisibilityLw(false);
}
}
@@ -2899,7 +2901,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.mAppOp != AppOpsManager.OP_NONE) {
final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
win.getOwningPackage());
- win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
+ win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED ||
+ mode == AppOpsManager.MODE_DEFAULT);
}
}
}
@@ -10307,7 +10310,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_VISIBILITY || DEBUG_POWER) {
Slog.v(TAG, "Turning screen on after layout!");
}
- mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.wm:TURN_ON");
}
mTurnOnScreen = false;
}
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 638783dcbbea..31763e7a90ba 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -35,6 +35,7 @@ import android.util.Slog;
import com.android.internal.alsa.AlsaCardsParser;
import com.android.internal.alsa.AlsaDevicesParser;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.audio.AudioService;
import libcore.io.IoUtils;
@@ -502,14 +503,14 @@ public final class UsbAlsaManager {
//
// Logging
//
- public void dump(FileDescriptor fd, PrintWriter pw) {
- pw.println(" USB Audio Devices:");
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("USB Audio Devices:");
for (UsbDevice device : mAudioDevices.keySet()) {
- pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device));
+ pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device));
}
- pw.println(" USB MIDI Devices:");
+ pw.println("USB MIDI Devices:");
for (UsbDevice device : mMidiDevices.keySet()) {
- pw.println(" " + device.getDeviceName() + ": " + mMidiDevices.get(device));
+ pw.println(" " + device.getDeviceName() + ": " + mMidiDevices.get(device));
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index 9a04e8bb278a..ae17fde347ff 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -38,6 +38,7 @@ import android.util.Base64;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
import java.io.File;
@@ -451,17 +452,17 @@ public class UsbDebuggingManager {
mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_CLEAR);
}
- public void dump(FileDescriptor fd, PrintWriter pw) {
- pw.println(" USB Debugging State:");
- pw.println(" Connected to adbd: " + (mThread != null));
- pw.println(" Last key received: " + mFingerprints);
- pw.println(" User keys:");
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("USB Debugging State:");
+ pw.println(" Connected to adbd: " + (mThread != null));
+ pw.println(" Last key received: " + mFingerprints);
+ pw.println(" User keys:");
try {
pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
} catch (IOException e) {
pw.println("IOException: " + e);
}
- pw.println(" System keys:");
+ pw.println(" System keys:");
try {
pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null));
} catch (IOException e) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 81b4857351c0..653cbd860982 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -45,6 +45,7 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
import java.io.File;
@@ -807,17 +808,17 @@ public class UsbDeviceManager {
UsbManager.USB_FUNCTION_ADB);
}
- public void dump(FileDescriptor fd, PrintWriter pw) {
- pw.println(" USB Device State:");
- pw.println(" mCurrentFunctions: " + mCurrentFunctions);
- pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
- pw.println(" mConnected: " + mConnected);
- pw.println(" mConfigured: " + mConfigured);
- pw.println(" mCurrentAccessory: " + mCurrentAccessory);
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("USB Device State:");
+ pw.println(" mCurrentFunctions: " + mCurrentFunctions);
+ pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
+ pw.println(" mConnected: " + mConnected);
+ pw.println(" mConfigured: " + mConfigured);
+ pw.println(" mCurrentAccessory: " + mCurrentAccessory);
try {
- pw.println(" Kernel state: "
+ pw.println(" Kernel state: "
+ FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
- pw.println(" Kernel function list: "
+ pw.println(" Kernel function list: "
+ FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
} catch (IOException e) {
pw.println("IOException: " + e);
@@ -908,12 +909,12 @@ public class UsbDeviceManager {
}
}
- public void dump(FileDescriptor fd, PrintWriter pw) {
+ public void dump(IndentingPrintWriter pw) {
if (mHandler != null) {
- mHandler.dump(fd, pw);
+ mHandler.dump(pw);
}
if (mDebuggingManager != null) {
- mDebuggingManager.dump(fd, pw);
+ mDebuggingManager.dump(pw);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index f5f2b07e3e93..6300a9a186cd 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -27,6 +27,7 @@ import android.os.ParcelFileDescriptor;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -283,11 +284,11 @@ public class UsbHostManager {
}
}
- public void dump(FileDescriptor fd, PrintWriter pw) {
+ public void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
- pw.println(" USB Host State:");
+ pw.println("USB Host State:");
for (String name : mDevices.keySet()) {
- pw.println(" " + name + ": " + mDevices.get(name));
+ pw.println(" " + name + ": " + mDevices.get(name));
}
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
new file mode 100644
index 000000000000..52abcfee0260
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -0,0 +1,753 @@
+/*
+ * 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.usb;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.FgThread;
+
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UEventObserver;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import libcore.io.IoUtils;
+
+/**
+ * Allows trusted components to control the properties of physical USB ports
+ * via the "/sys/class/dual_role_usb" kernel interface.
+ * <p>
+ * Note: This interface may not be supported on all chipsets since the USB drivers
+ * must be changed to publish this information through the module. At the moment
+ * we only need this for devices with USB Type C ports to allow the System UI to
+ * control USB charging and data direction. On devices that do not support this
+ * interface the list of ports may incorrectly appear to be empty
+ * (but we don't care today).
+ * </p>
+ */
+public class UsbPortManager {
+ private static final String TAG = "UsbPortManager";
+
+ private static final int MSG_UPDATE_PORTS = 1;
+
+ // UEvent path to watch.
+ private static final String UEVENT_FILTER = "SUBSYSTEM=dual_role_usb";
+
+ // SysFS directory that contains USB ports as subdirectories.
+ private static final String SYSFS_CLASS = "/sys/class/dual_role_usb";
+
+ // SysFS file that contains a USB port's supported modes. (read-only)
+ // Contents: "", "ufp", "dfp", or "ufp dfp".
+ private static final String SYSFS_PORT_SUPPORTED_MODES = "supported_modes";
+
+ // SysFS file that contains a USB port's current mode. (read-write if configurable)
+ // Contents: "", "ufp", or "dfp".
+ private static final String SYSFS_PORT_MODE = "mode";
+
+ // SysFS file that contains a USB port's current power role. (read-write if configurable)
+ // Contents: "", "source", or "sink".
+ private static final String SYSFS_PORT_POWER_ROLE = "power_role";
+
+ // SysFS file that contains a USB port's current data role. (read-write if configurable)
+ // Contents: "", "host", or "device".
+ private static final String SYSFS_PORT_DATA_ROLE = "data_role";
+
+ // Port modes: upstream facing port or downstream facing port.
+ private static final String PORT_MODE_DFP = "dfp";
+ private static final String PORT_MODE_UFP = "ufp";
+
+ // Port power roles: source or sink.
+ private static final String PORT_POWER_ROLE_SOURCE = "source";
+ private static final String PORT_POWER_ROLE_SINK = "sink";
+
+ // Port data roles: host or device.
+ private static final String PORT_DATA_ROLE_HOST = "host";
+ private static final String PORT_DATA_ROLE_DEVICE = "device";
+
+ // All non-trivial role combinations.
+ private static final int COMBO_SOURCE_HOST =
+ UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
+ private static final int COMBO_SOURCE_DEVICE =
+ UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE);
+ private static final int COMBO_SINK_HOST =
+ UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST);
+ private static final int COMBO_SINK_DEVICE =
+ UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+
+ // The system context.
+ private final Context mContext;
+
+ // True if we have kernel support.
+ private final boolean mHaveKernelSupport;
+
+ // Mutex for all mutable shared state.
+ private final Object mLock = new Object();
+
+ // List of all ports, indexed by id.
+ // Ports may temporarily have different dispositions as they are added or removed
+ // but the class invariant is that this list will only contain ports with DISPOSITION_READY
+ // except while updatePortsLocked() is in progress.
+ private final ArrayMap<String, PortInfo> mPorts = new ArrayMap<String, PortInfo>();
+
+ // List of all simulated ports, indexed by id.
+ private final ArrayMap<String, SimulatedPortInfo> mSimulatedPorts =
+ new ArrayMap<String, SimulatedPortInfo>();
+
+ public UsbPortManager(Context context) {
+ mContext = context;
+ mHaveKernelSupport = new File(SYSFS_CLASS).exists();
+ }
+
+ public void systemReady() {
+ mUEventObserver.startObserving(UEVENT_FILTER);
+ scheduleUpdatePorts();
+ }
+
+ public UsbPort[] getPorts() {
+ synchronized (mLock) {
+ final int count = mPorts.size();
+ final UsbPort[] result = new UsbPort[count];
+ for (int i = 0; i < count; i++) {
+ result[i] = mPorts.valueAt(i).mUsbPort;
+ }
+ return result;
+ }
+ }
+
+ public UsbPortStatus getPortStatus(String portId) {
+ synchronized (mLock) {
+ final PortInfo portInfo = mPorts.get(portId);
+ return portInfo != null ? portInfo.mUsbPortStatus : null;
+ }
+ }
+
+ public void setPortRoles(String portId, int newPowerRole, int newDataRole,
+ IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ final PortInfo portInfo = mPorts.get(portId);
+ if (portInfo == null) {
+ if (pw != null) {
+ pw.println("No such USB port: " + portId);
+ }
+ return;
+ }
+
+ // Check whether the new role is actually supported.
+ if (!portInfo.mUsbPortStatus.isRoleCombinationSupported(newPowerRole, newDataRole)) {
+ logAndPrint(Log.ERROR, pw, "Attempted to set USB port into unsupported "
+ + "role combination: portId=" + portId
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
+ return;
+ }
+
+ // Check whether anything actually changed.
+ final int currentDataRole = portInfo.mUsbPortStatus.getCurrentDataRole();
+ final int currentPowerRole = portInfo.mUsbPortStatus.getCurrentPowerRole();
+ if (currentDataRole == newDataRole && currentPowerRole == newPowerRole) {
+ if (pw != null) {
+ pw.println("No change.");
+ }
+ return;
+ }
+
+ // Determine whether we need to change the mode in order to accomplish this goal.
+ // We prefer not to do this since it's more likely to fail.
+ //
+ // Note: Arguably it might be worth allowing the client to influence this policy
+ // decision so that we could show more powerful developer facing UI but let's
+ // see how far we can get without having to do that.
+ final boolean canChangeMode = portInfo.mCanChangeMode;
+ final boolean canChangePowerRole = portInfo.mCanChangePowerRole;
+ final boolean canChangeDataRole = portInfo.mCanChangeDataRole;
+ final int currentMode = portInfo.mUsbPortStatus.getCurrentMode();
+ final int newMode;
+ if ((!canChangePowerRole && currentPowerRole != newPowerRole)
+ || (!canChangeDataRole && currentDataRole != newDataRole)) {
+ if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SOURCE
+ && newDataRole == UsbPort.DATA_ROLE_HOST) {
+ newMode = UsbPort.MODE_DFP;
+ } else if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SINK
+ && newDataRole == UsbPort.DATA_ROLE_DEVICE) {
+ newMode = UsbPort.MODE_UFP;
+ } else {
+ logAndPrint(Log.ERROR, pw, "Found mismatch in supported USB role combinations "
+ + "while attempting to change role: " + portInfo
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
+ return;
+ }
+ } else {
+ newMode = currentMode;
+ }
+
+ // Make it happen.
+ logAndPrint(Log.INFO, pw, "Setting USB port mode and role: portId=" + portId
+ + ", currentMode=" + UsbPort.modeToString(currentMode)
+ + ", currentPowerRole=" + UsbPort.powerRoleToString(currentPowerRole)
+ + ", currentDataRole=" + UsbPort.dataRoleToString(currentDataRole)
+ + ", newMode=" + UsbPort.modeToString(newMode)
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
+
+ SimulatedPortInfo sim = mSimulatedPorts.get(portId);
+ if (sim != null) {
+ // Change simulated state.
+ sim.mCurrentMode = newMode;
+ sim.mCurrentPowerRole = newPowerRole;
+ sim.mCurrentDataRole = newDataRole;
+ } else if (mHaveKernelSupport) {
+ // Change actual state.
+ final File portDir = new File(SYSFS_CLASS, portId);
+ if (!portDir.exists()) {
+ logAndPrint(Log.ERROR, pw, "USB port not found: portId=" + portId);
+ return;
+ }
+
+ if (currentMode != newMode) {
+ // Changing the mode will have the side-effect of also changing
+ // the power and data roles but it might take some time to apply
+ // and the renegotiation might fail. Due to limitations of the USB
+ // hardware, we have no way of knowing whether it will work apriori
+ // which is why we would prefer to set the power and data roles
+ // directly instead.
+ if (!writeFile(portDir, SYSFS_PORT_MODE,
+ newMode == UsbPort.MODE_DFP ? PORT_MODE_DFP : PORT_MODE_UFP)) {
+ logAndPrint(Log.ERROR, pw, "Failed to set the USB port mode: "
+ + "portId=" + portId
+ + ", newMode=" + UsbPort.modeToString(newMode));
+ return;
+ }
+ } else {
+ // Change power and data role independently as needed.
+ if (currentPowerRole != newPowerRole) {
+ if (!writeFile(portDir, SYSFS_PORT_POWER_ROLE,
+ newPowerRole == UsbPort.POWER_ROLE_SOURCE
+ ? PORT_POWER_ROLE_SOURCE : PORT_POWER_ROLE_SINK)) {
+ logAndPrint(Log.ERROR, pw, "Failed to set the USB port power role: "
+ + "portId=" + portId
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole));
+ return;
+ }
+ }
+ if (currentDataRole != newDataRole) {
+ if (!writeFile(portDir, SYSFS_PORT_DATA_ROLE,
+ newDataRole == UsbPort.DATA_ROLE_HOST
+ ? PORT_DATA_ROLE_HOST : PORT_DATA_ROLE_DEVICE)) {
+ logAndPrint(Log.ERROR, pw, "Failed to set the USB port data role: "
+ + "portId=" + portId
+ + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
+ return;
+ }
+ }
+ }
+ }
+ updatePortsLocked(pw);
+ }
+ }
+
+ public void addSimulatedPort(String portId, int supportedModes, IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ if (mSimulatedPorts.containsKey(portId)) {
+ pw.println("Port with same name already exists. Please remove it first.");
+ return;
+ }
+
+ pw.println("Adding simulated port: portId=" + portId
+ + ", supportedModes=" + UsbPort.modeToString(supportedModes));
+ mSimulatedPorts.put(portId,
+ new SimulatedPortInfo(portId, supportedModes));
+ updatePortsLocked(pw);
+ }
+ }
+
+ public void connectSimulatedPort(String portId, int mode, boolean canChangeMode,
+ int powerRole, boolean canChangePowerRole,
+ int dataRole, boolean canChangeDataRole, IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId);
+ if (portInfo == null) {
+ pw.println("Cannot connect simulated port which does not exist.");
+ return;
+ }
+
+ if (mode == 0 || powerRole == 0 || dataRole == 0) {
+ pw.println("Cannot connect simulated port in null mode, "
+ + "power role, or data role.");
+ return;
+ }
+
+ if ((portInfo.mSupportedModes & mode) == 0) {
+ pw.println("Simulated port does not support mode: " + UsbPort.modeToString(mode));
+ return;
+ }
+
+ pw.println("Connecting simulated port: portId=" + portId
+ + ", mode=" + UsbPort.modeToString(mode)
+ + ", canChangeMode=" + canChangeMode
+ + ", powerRole=" + UsbPort.powerRoleToString(powerRole)
+ + ", canChangePowerRole=" + canChangePowerRole
+ + ", dataRole=" + UsbPort.dataRoleToString(dataRole)
+ + ", canChangeDataRole=" + canChangeDataRole);
+ portInfo.mCurrentMode = mode;
+ portInfo.mCanChangeMode = canChangeMode;
+ portInfo.mCurrentPowerRole = powerRole;
+ portInfo.mCanChangePowerRole = canChangePowerRole;
+ portInfo.mCurrentDataRole = dataRole;
+ portInfo.mCanChangeDataRole = canChangeDataRole;
+ updatePortsLocked(pw);
+ }
+ }
+
+ public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId);
+ if (portInfo == null) {
+ pw.println("Cannot disconnect simulated port which does not exist.");
+ return;
+ }
+
+ pw.println("Disconnecting simulated port: portId=" + portId);
+ portInfo.mCurrentMode = 0;
+ portInfo.mCanChangeMode = false;
+ portInfo.mCurrentPowerRole = 0;
+ portInfo.mCanChangePowerRole = false;
+ portInfo.mCurrentDataRole = 0;
+ portInfo.mCanChangeDataRole = false;
+ updatePortsLocked(pw);
+ }
+ }
+
+ public void removeSimulatedPort(String portId, IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ final int index = mSimulatedPorts.indexOfKey(portId);
+ if (index < 0) {
+ pw.println("Cannot remove simulated port which does not exist.");
+ return;
+ }
+
+ pw.println("Disconnecting simulated port: portId=" + portId);
+ mSimulatedPorts.removeAt(index);
+ updatePortsLocked(pw);
+ }
+ }
+
+ public void resetSimulation(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ pw.println("Removing all simulated ports and ending simulation.");
+ if (!mSimulatedPorts.isEmpty()) {
+ mSimulatedPorts.clear();
+ updatePortsLocked(pw);
+ }
+ }
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ pw.print("USB Port State:");
+ if (!mSimulatedPorts.isEmpty()) {
+ pw.print(" (simulation active; end with 'dumpsys usb reset')");
+ }
+ pw.println();
+
+ if (mPorts.isEmpty()) {
+ pw.println(" <no ports>");
+ } else {
+ for (PortInfo portInfo : mPorts.values()) {
+ pw.println(" " + portInfo.mUsbPort.getId() + ": " + portInfo);
+ }
+ }
+ }
+ }
+
+ private void updatePortsLocked(IndentingPrintWriter pw) {
+ // Assume all ports are gone unless informed otherwise.
+ // Kind of pessimistic but simple.
+ for (int i = mPorts.size(); i-- > 0; ) {
+ mPorts.valueAt(i).mDisposition = PortInfo.DISPOSITION_REMOVED;
+ }
+
+ // Enumerate all extant ports.
+ if (!mSimulatedPorts.isEmpty()) {
+ final int count = mSimulatedPorts.size();
+ for (int i = 0; i < count; i++) {
+ final SimulatedPortInfo portInfo = mSimulatedPorts.valueAt(i);
+ addOrUpdatePortLocked(portInfo.mPortId, portInfo.mSupportedModes,
+ portInfo.mCurrentMode, portInfo.mCanChangeMode,
+ portInfo.mCurrentPowerRole, portInfo.mCanChangePowerRole,
+ portInfo.mCurrentDataRole, portInfo.mCanChangeDataRole, pw);
+ }
+ } else if (mHaveKernelSupport) {
+ final File[] portDirs = new File(SYSFS_CLASS).listFiles();
+ if (portDirs != null) {
+ for (File portDir : portDirs) {
+ if (!portDir.isDirectory()) {
+ continue;
+ }
+
+ // Parse the sysfs file contents.
+ final String portId = portDir.getName();
+ final int supportedModes = readSupportedModes(portDir);
+ final int currentMode = readCurrentMode(portDir);
+ final boolean canChangeMode = canChangeMode(portDir);
+ final int currentPowerRole = readCurrentPowerRole(portDir);
+ final boolean canChangePowerRole = canChangePowerRole(portDir);
+ final int currentDataRole = readCurrentDataRole(portDir);
+ final boolean canChangeDataRole = canChangeDataRole(portDir);
+ addOrUpdatePortLocked(portId, supportedModes,
+ currentMode, canChangeMode,
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole, pw);
+ }
+ }
+ }
+
+ // Process the updates.
+ // Once finished, the list of ports will only contain ports in DISPOSITION_READY.
+ for (int i = mPorts.size(); i-- > 0; ) {
+ final PortInfo portInfo = mPorts.valueAt(i);
+ switch (portInfo.mDisposition) {
+ case PortInfo.DISPOSITION_ADDED:
+ handlePortAddedLocked(portInfo, pw);
+ portInfo.mDisposition = PortInfo.DISPOSITION_READY;
+ break;
+ case PortInfo.DISPOSITION_CHANGED:
+ handlePortChangedLocked(portInfo, pw);
+ portInfo.mDisposition = PortInfo.DISPOSITION_READY;
+ break;
+ case PortInfo.DISPOSITION_REMOVED:
+ mPorts.removeAt(i);
+ portInfo.mUsbPortStatus = null; // must do this early
+ handlePortRemovedLocked(portInfo, pw);
+ break;
+ }
+ }
+ }
+
+ // Must only be called by updatePortsLocked.
+ private void addOrUpdatePortLocked(String portId, int supportedModes,
+ int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole,
+ IndentingPrintWriter pw) {
+ // Only allow mode switch capability for dual role ports.
+ // Validate that the current mode matches the supported modes we expect.
+ if (supportedModes != UsbPort.MODE_DUAL) {
+ canChangeMode = false;
+ if (currentMode != 0 && currentMode != supportedModes) {
+ logAndPrint(Log.WARN, pw, "Ignoring inconsistent current mode from USB "
+ + "port driver: supportedModes=" + UsbPort.modeToString(supportedModes)
+ + ", currentMode=" + UsbPort.modeToString(currentMode));
+ currentMode = 0;
+ }
+ }
+
+ // Determine the supported role combinations.
+ // Note that the policy is designed to prefer setting the power and data
+ // role independently rather than changing the mode.
+ int supportedRoleCombinations = UsbPort.combineRolesAsBit(
+ currentPowerRole, currentDataRole);
+ if (currentMode != 0 && currentPowerRole != 0 && currentDataRole != 0) {
+ if (canChangePowerRole && canChangeDataRole) {
+ // Can change both power and data role independently.
+ // Assume all combinations are possible.
+ supportedRoleCombinations |=
+ COMBO_SOURCE_HOST | COMBO_SOURCE_DEVICE
+ | COMBO_SINK_HOST | COMBO_SINK_DEVICE;
+ } else if (canChangePowerRole) {
+ // Can only change power role.
+ // Assume data role must remain at its current value.
+ supportedRoleCombinations |= UsbPort.combineRolesAsBit(
+ UsbPort.POWER_ROLE_SOURCE, currentDataRole);
+ supportedRoleCombinations |= UsbPort.combineRolesAsBit(
+ UsbPort.POWER_ROLE_SINK, currentDataRole);
+ } else if (canChangeDataRole) {
+ // Can only change data role.
+ // Assume power role must remain at its current value.
+ supportedRoleCombinations |= UsbPort.combineRolesAsBit(
+ currentPowerRole, UsbPort.DATA_ROLE_HOST);
+ supportedRoleCombinations |= UsbPort.combineRolesAsBit(
+ currentPowerRole, UsbPort.DATA_ROLE_DEVICE);
+ } else if (canChangeMode) {
+ // Can only change the mode.
+ // Assume both standard UFP and DFP configurations will become available
+ // when this happens.
+ supportedRoleCombinations |= COMBO_SOURCE_HOST | COMBO_SINK_DEVICE;
+ }
+ }
+
+ // Update the port data structures.
+ PortInfo portInfo = mPorts.get(portId);
+ if (portInfo == null) {
+ portInfo = new PortInfo(portId, supportedModes);
+ portInfo.setStatus(currentMode, canChangeMode,
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportedRoleCombinations);
+ mPorts.put(portId, portInfo);
+ } else {
+ // Sanity check that ports aren't changing definition out from under us.
+ if (supportedModes != portInfo.mUsbPort.getSupportedModes()) {
+ logAndPrint(Log.WARN, pw, "Ignoring inconsistent list of supported modes from "
+ + "USB port driver (should be immutable): "
+ + "previous=" + UsbPort.modeToString(
+ portInfo.mUsbPort.getSupportedModes())
+ + ", current=" + UsbPort.modeToString(supportedModes));
+ }
+
+ if (portInfo.setStatus(currentMode, canChangeMode,
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportedRoleCombinations)) {
+ portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
+ } else {
+ portInfo.mDisposition = PortInfo.DISPOSITION_READY;
+ }
+ }
+ }
+
+ private void handlePortAddedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
+ logAndPrint(Log.INFO, pw, "USB port added: " + portInfo);
+ sendPortChangedBroadcastLocked(portInfo);
+ }
+
+ private void handlePortChangedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
+ logAndPrint(Log.INFO, pw, "USB port changed: " + portInfo);
+ sendPortChangedBroadcastLocked(portInfo);
+ }
+
+ private void handlePortRemovedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
+ logAndPrint(Log.INFO, pw, "USB port removed: " + portInfo);
+ sendPortChangedBroadcastLocked(portInfo);
+ }
+
+ private void sendPortChangedBroadcastLocked(PortInfo portInfo) {
+ final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(UsbManager.EXTRA_PORT, portInfo.mUsbPort);
+ intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus);
+
+ // Guard against possible reentrance by posting the broadcast from the handler
+ // instead of from within the critical section.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+ });
+ }
+
+ private void scheduleUpdatePorts() {
+ if (!mHandler.hasMessages(MSG_UPDATE_PORTS)) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_PORTS);
+ }
+ }
+
+ private static int readSupportedModes(File portDir) {
+ int modes = 0;
+ final String contents = readFile(portDir, SYSFS_PORT_SUPPORTED_MODES);
+ if (contents != null) {
+ if (contents.contains(PORT_MODE_DFP)) {
+ modes |= UsbPort.MODE_DFP;
+ }
+ if (contents.contains(PORT_MODE_UFP)) {
+ modes |= UsbPort.MODE_UFP;
+ }
+ }
+ return modes;
+ }
+
+ private static int readCurrentMode(File portDir) {
+ final String contents = readFile(portDir, SYSFS_PORT_MODE);
+ if (contents != null) {
+ if (contents.equals(PORT_MODE_DFP)) {
+ return UsbPort.MODE_DFP;
+ }
+ if (contents.equals(PORT_MODE_UFP)) {
+ return UsbPort.MODE_UFP;
+ }
+ }
+ return 0;
+ }
+
+ private static int readCurrentPowerRole(File portDir) {
+ final String contents = readFile(portDir, SYSFS_PORT_POWER_ROLE);
+ if (contents != null) {
+ if (contents.equals(PORT_POWER_ROLE_SOURCE)) {
+ return UsbPort.POWER_ROLE_SOURCE;
+ }
+ if (contents.equals(PORT_POWER_ROLE_SINK)) {
+ return UsbPort.POWER_ROLE_SINK;
+ }
+ }
+ return 0;
+ }
+
+ private static int readCurrentDataRole(File portDir) {
+ final String contents = readFile(portDir, SYSFS_PORT_DATA_ROLE);
+ if (contents != null) {
+ if (contents.equals(PORT_DATA_ROLE_HOST)) {
+ return UsbPort.DATA_ROLE_HOST;
+ }
+ if (contents.equals(PORT_DATA_ROLE_DEVICE)) {
+ return UsbPort.DATA_ROLE_DEVICE;
+ }
+ }
+ return 0;
+ }
+
+ private static boolean canChangeMode(File portDir) {
+ return new File(portDir, SYSFS_PORT_MODE).canWrite();
+ }
+
+ private static boolean canChangePowerRole(File portDir) {
+ return new File(portDir, SYSFS_PORT_POWER_ROLE).canWrite();
+ }
+
+ private static boolean canChangeDataRole(File portDir) {
+ return new File(portDir, SYSFS_PORT_DATA_ROLE).canWrite();
+ }
+
+ private static String readFile(File dir, String filename) {
+ final File file = new File(dir, filename);
+ try {
+ return IoUtils.readFileAsString(file.getAbsolutePath()).trim();
+ } catch (IOException ex) {
+ return null;
+ }
+ }
+
+ private static boolean writeFile(File dir, String filename, String contents) {
+ final File file = new File(dir, filename);
+ try {
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(contents);
+ }
+ return true;
+ } catch (IOException ex) {
+ return false;
+ }
+ }
+
+ private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+ Slog.println(priority, TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ }
+ }
+
+ private final Handler mHandler = new Handler(FgThread.get().getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_PORTS: {
+ synchronized (mLock) {
+ updatePortsLocked(null);
+ }
+ break;
+ }
+ }
+ }
+ };
+
+ private final UEventObserver mUEventObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEvent event) {
+ scheduleUpdatePorts();
+ }
+ };
+
+ /**
+ * Describes a USB port.
+ */
+ private static final class PortInfo {
+ public static final int DISPOSITION_ADDED = 0;
+ public static final int DISPOSITION_CHANGED = 1;
+ public static final int DISPOSITION_READY = 2;
+ public static final int DISPOSITION_REMOVED = 3;
+
+ public final UsbPort mUsbPort;
+ public UsbPortStatus mUsbPortStatus;
+ public boolean mCanChangeMode;
+ public boolean mCanChangePowerRole;
+ public boolean mCanChangeDataRole;
+ public int mDisposition; // default initialized to 0 which means added
+
+ public PortInfo(String portId, int supportedModes) {
+ mUsbPort = new UsbPort(portId, supportedModes);
+ }
+
+ public boolean setStatus(int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole,
+ int supportedRoleCombinations) {
+ mCanChangeMode = canChangeMode;
+ mCanChangePowerRole = canChangePowerRole;
+ mCanChangeDataRole = canChangeDataRole;
+ if (mUsbPortStatus == null
+ || mUsbPortStatus.getCurrentMode() != currentMode
+ || mUsbPortStatus.getCurrentPowerRole() != currentPowerRole
+ || mUsbPortStatus.getCurrentDataRole() != currentDataRole
+ || mUsbPortStatus.getSupportedRoleCombinations()
+ != supportedRoleCombinations) {
+ mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
+ supportedRoleCombinations);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "port=" + mUsbPort + ", status=" + mUsbPortStatus
+ + ", canChangeMode=" + mCanChangeMode
+ + ", canChangePowerRole=" + mCanChangePowerRole
+ + ", canChangeDataRole=" + mCanChangeDataRole;
+ }
+ }
+
+ /**
+ * Describes a simulated USB port.
+ * Roughly mirrors the information we would ordinarily get from the kernel.
+ */
+ private static final class SimulatedPortInfo {
+ public final String mPortId;
+ public final int mSupportedModes;
+ public int mCurrentMode;
+ public boolean mCanChangeMode;
+ public int mCurrentPowerRole;
+ public boolean mCanChangePowerRole;
+ public int mCurrentDataRole;
+ public boolean mCanChangeDataRole;
+
+ public SimulatedPortInfo(String portId, int supportedModes) {
+ mPortId = portId;
+ mSupportedModes = supportedModes;
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index c8b42262be67..f93a2ef1adce 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -27,6 +27,9 @@ import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
@@ -36,6 +39,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import java.io.File;
@@ -78,6 +82,7 @@ public class UsbService extends IUsbManager.Stub {
private UsbDeviceManager mDeviceManager;
private UsbHostManager mHostManager;
+ private UsbPortManager mPortManager;
private final UsbAlsaManager mAlsaManager;
private final Object mLock = new Object();
@@ -110,6 +115,9 @@ public class UsbService extends IUsbManager.Stub {
if (new File("/sys/class/android_usb").exists()) {
mDeviceManager = new UsbDeviceManager(context, mAlsaManager);
}
+ if (mHostManager != null || mDeviceManager != null) {
+ mPortManager = new UsbPortManager(context);
+ }
setCurrentUser(UserHandle.USER_OWNER);
@@ -160,6 +168,9 @@ public class UsbService extends IUsbManager.Stub {
if (mHostManager != null) {
mHostManager.systemReady();
}
+ if (mPortManager != null) {
+ mPortManager.systemReady();
+ }
}
public void bootCompleted() {
@@ -346,29 +357,258 @@ public class UsbService extends IUsbManager.Stub {
}
@Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
- final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ public UsbPort[] getPorts() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- pw.println("USB Manager State:");
- if (mDeviceManager != null) {
- mDeviceManager.dump(fd, pw);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mPortManager != null ? mPortManager.getPorts() : null;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- if (mHostManager != null) {
- mHostManager.dump(fd, pw);
+ }
+
+ @Override
+ public UsbPortStatus getPortStatus(String portId) {
+ Preconditions.checkNotNull(portId, "portId must not be null");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mPortManager != null ? mPortManager.getPortStatus(portId) : null;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- mAlsaManager.dump(fd, pw);
+ }
- synchronized (mLock) {
- for (int i = 0; i < mSettingsByUser.size(); i++) {
- final int userId = mSettingsByUser.keyAt(i);
- final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
+ @Override
+ public void setPortRoles(String portId, int powerRole, int dataRole) {
+ Preconditions.checkNotNull(portId, "portId must not be null");
+ UsbPort.checkRoles(powerRole, dataRole);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mPortManager != null) {
+ mPortManager.setPortRoles(portId, powerRole, dataRole, null);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (args == null || args.length == 0 || "-a".equals(args[0])) {
+ pw.println("USB Manager State:");
pw.increaseIndent();
- pw.println("Settings for user " + userId + ":");
- settings.dump(fd, pw);
- pw.decreaseIndent();
+ if (mDeviceManager != null) {
+ mDeviceManager.dump(pw);
+ }
+ if (mHostManager != null) {
+ mHostManager.dump(pw);
+ }
+ if (mPortManager != null) {
+ mPortManager.dump(pw);
+ }
+ mAlsaManager.dump(pw);
+
+ synchronized (mLock) {
+ for (int i = 0; i < mSettingsByUser.size(); i++) {
+ final int userId = mSettingsByUser.keyAt(i);
+ final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
+ pw.println("Settings for user " + userId + ":");
+ pw.increaseIndent();
+ settings.dump(pw);
+ pw.decreaseIndent();
+ }
+ }
+ } else if (args.length == 4 && "set-port-roles".equals(args[0])) {
+ final String portId = args[1];
+ final int powerRole;
+ switch (args[2]) {
+ case "source":
+ powerRole = UsbPort.POWER_ROLE_SOURCE;
+ break;
+ case "sink":
+ powerRole = UsbPort.POWER_ROLE_SINK;
+ break;
+ case "no-power":
+ powerRole = 0;
+ break;
+ default:
+ pw.println("Invalid power role: " + args[2]);
+ return;
+ }
+ final int dataRole;
+ switch (args[3]) {
+ case "host":
+ dataRole = UsbPort.DATA_ROLE_HOST;
+ break;
+ case "device":
+ dataRole = UsbPort.DATA_ROLE_DEVICE;
+ break;
+ case "no-data":
+ dataRole = 0;
+ break;
+ default:
+ pw.println("Invalid data role: " + args[3]);
+ return;
+ }
+ if (mPortManager != null) {
+ mPortManager.setPortRoles(portId, powerRole, dataRole, pw);
+ // Note: It might take some time for the side-effects of this operation
+ // to be fully applied by the kernel since the driver may need to
+ // renegotiate the USB port mode. If this proves to be an issue
+ // during debugging, it might be worth adding a sleep here before
+ // dumping the new state.
+ pw.println();
+ mPortManager.dump(pw);
+ }
+ } else if (args.length == 3 && "add-port".equals(args[0])) {
+ final String portId = args[1];
+ final int supportedModes;
+ switch (args[2]) {
+ case "ufp":
+ supportedModes = UsbPort.MODE_UFP;
+ break;
+ case "dfp":
+ supportedModes = UsbPort.MODE_DFP;
+ break;
+ case "dual":
+ supportedModes = UsbPort.MODE_DUAL;
+ break;
+ case "none":
+ supportedModes = 0;
+ break;
+ default:
+ pw.println("Invalid mode: " + args[2]);
+ return;
+ }
+ if (mPortManager != null) {
+ mPortManager.addSimulatedPort(portId, supportedModes, pw);
+ pw.println();
+ mPortManager.dump(pw);
+ }
+ } else if (args.length == 5 && "connect-port".equals(args[0])) {
+ final String portId = args[1];
+ final int mode;
+ final boolean canChangeMode = args[2].endsWith("?");
+ switch (canChangeMode ? removeLastChar(args[2]) : args[2]) {
+ case "ufp":
+ mode = UsbPort.MODE_UFP;
+ break;
+ case "dfp":
+ mode = UsbPort.MODE_DFP;
+ break;
+ default:
+ pw.println("Invalid mode: " + args[2]);
+ return;
+ }
+ final int powerRole;
+ final boolean canChangePowerRole = args[3].endsWith("?");
+ switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) {
+ case "source":
+ powerRole = UsbPort.POWER_ROLE_SOURCE;
+ break;
+ case "sink":
+ powerRole = UsbPort.POWER_ROLE_SINK;
+ break;
+ default:
+ pw.println("Invalid power role: " + args[3]);
+ return;
+ }
+ final int dataRole;
+ final boolean canChangeDataRole = args[4].endsWith("?");
+ switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) {
+ case "host":
+ dataRole = UsbPort.DATA_ROLE_HOST;
+ break;
+ case "device":
+ dataRole = UsbPort.DATA_ROLE_DEVICE;
+ break;
+ default:
+ pw.println("Invalid data role: " + args[4]);
+ return;
+ }
+ if (mPortManager != null) {
+ mPortManager.connectSimulatedPort(portId, mode, canChangeMode,
+ powerRole, canChangePowerRole, dataRole, canChangeDataRole, pw);
+ pw.println();
+ mPortManager.dump(pw);
+ }
+ } else if (args.length == 2 && "disconnect-port".equals(args[0])) {
+ final String portId = args[1];
+ if (mPortManager != null) {
+ mPortManager.disconnectSimulatedPort(portId, pw);
+ pw.println();
+ mPortManager.dump(pw);
+ }
+ } else if (args.length == 2 && "remove-port".equals(args[0])) {
+ final String portId = args[1];
+ if (mPortManager != null) {
+ mPortManager.removeSimulatedPort(portId, pw);
+ pw.println();
+ mPortManager.dump(pw);
+ }
+ } else if (args.length == 1 && "reset".equals(args[0])) {
+ if (mPortManager != null) {
+ mPortManager.resetSimulation(pw);
+ pw.println();
+ mPortManager.dump(pw);
+ }
+ } else if (args.length == 1 && "ports".equals(args[0])) {
+ if (mPortManager != null) {
+ mPortManager.dump(pw);
+ }
+ } else {
+ pw.println("Dump current USB state or issue command:");
+ pw.println(" ports");
+ pw.println(" set-port-roles <id> <source|sink|no-power> <host|device|no-data>");
+ pw.println(" add-port <id> <ufp|dfp|dual|none>");
+ pw.println(" connect-port <id> <ufp|dfp><?> <source|sink><?> <host|device><?>");
+ pw.println(" (add ? suffix if mode, power role, or data role can be changed)");
+ pw.println(" disconnect-port <id>");
+ pw.println(" remove-port <id>");
+ pw.println(" reset");
+ pw.println();
+ pw.println("Example USB type C port role switch:");
+ pw.println(" dumpsys usb set-port-roles \"default\" source device");
+ pw.println();
+ pw.println("Example USB type C port simulation with full capabilities:");
+ pw.println(" dumpsys usb add-port \"matrix\" dual");
+ pw.println(" dumpsys usb connect-port \"matrix\" ufp? sink? device?");
+ pw.println(" dumpsys usb ports");
+ pw.println(" dumpsys usb disconnect-port \"matrix\"");
+ pw.println(" dumpsys usb remove-port \"matrix\"");
+ pw.println(" dumpsys usb reset");
+ pw.println();
+ pw.println("Example USB type C port where only power role can be changed:");
+ pw.println(" dumpsys usb add-port \"matrix\" dual");
+ pw.println(" dumpsys usb connect-port \"matrix\" dfp source? host");
+ pw.println(" dumpsys usb reset");
+ pw.println();
+ pw.println("Example USB OTG port where id pin determines function:");
+ pw.println(" dumpsys usb add-port \"matrix\" dual");
+ pw.println(" dumpsys usb connect-port \"matrix\" dfp source host");
+ pw.println(" dumpsys usb reset");
+ pw.println();
+ pw.println("Example USB device-only port:");
+ pw.println(" dumpsys usb add-port \"matrix\" ufp");
+ pw.println(" dumpsys usb connect-port \"matrix\" ufp sink device");
+ pw.println(" dumpsys usb reset");
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- pw.decreaseIndent();
+ }
+
+ private static final String removeLastChar(String value) {
+ return value.substring(0, value.length() - 1);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 2331a8b1c69a..2cf42f09111d 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -44,6 +44,7 @@ import android.util.Xml;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -1193,35 +1194,35 @@ class UsbSettingsManager {
}
}
- public void dump(FileDescriptor fd, PrintWriter pw) {
+ public void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
- pw.println(" Device permissions:");
+ pw.println("Device permissions:");
for (String deviceName : mDevicePermissionMap.keySet()) {
- pw.print(" " + deviceName + ": ");
+ pw.print(" " + deviceName + ": ");
SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
int count = uidList.size();
for (int i = 0; i < count; i++) {
pw.print(Integer.toString(uidList.keyAt(i)) + " ");
}
- pw.println("");
+ pw.println();
}
- pw.println(" Accessory permissions:");
+ pw.println("Accessory permissions:");
for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
- pw.print(" " + accessory + ": ");
+ pw.print(" " + accessory + ": ");
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
int count = uidList.size();
for (int i = 0; i < count; i++) {
pw.print(Integer.toString(uidList.keyAt(i)) + " ");
}
- pw.println("");
+ pw.println();
}
- pw.println(" Device preferences:");
+ pw.println("Device preferences:");
for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
- pw.println(" " + filter + ": " + mDevicePreferenceMap.get(filter));
+ pw.println(" " + filter + ": " + mDevicePreferenceMap.get(filter));
}
- pw.println(" Accessory preferences:");
+ pw.println("Accessory preferences:");
for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
- pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter));
+ pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter));
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 36478daaf5fd..42f879c8a992 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -578,6 +578,44 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Override
+ public void setDisabledShowContext(int flags) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
+ return;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.setDisabledShowContextLocked(callingPid, callingUid, flags);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ }
+
+ @Override
+ public int getDisabledShowContext() {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
+ return 0;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.getDisabledShowContextLocked(callingPid, callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ }
+
//----------------- Model management APIs --------------------------------//
@Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e5faf4db117a..7409f99ded51 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -65,6 +65,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
IVoiceInteractionService mService;
VoiceInteractionSessionConnection mActiveSession;
+ int mDisabledShowContext;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -146,7 +147,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
}
- return mActiveSession.showLocked(args, flags, showCallback);
+ return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback);
}
public boolean hideSessionLocked() {
@@ -222,6 +223,24 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
mActiveSession = null;
}
+ public void setDisabledShowContextLocked(int callingPid, int callingUid, int flags) {
+ int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
+ if (callingUid != activeUid) {
+ throw new SecurityException("Calling uid " + callingUid
+ + " does not match active uid " + activeUid);
+ }
+ mDisabledShowContext = flags;
+ }
+
+ public int getDisabledShowContextLocked(int callingPid, int callingUid) {
+ int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
+ if (callingUid != activeUid) {
+ throw new SecurityException("Calling uid " + callingUid
+ + " does not match active uid " + activeUid);
+ }
+ return mDisabledShowContext;
+ }
+
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!mValid) {
pw.print(" NOT VALID: ");
@@ -235,6 +254,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
pw.print(" mComponent="); pw.println(mComponent.flattenToShortString());
pw.print(" Session service="); pw.println(mInfo.getSessionService());
pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity());
+ if (mDisabledShowContext != 0) {
+ pw.print(" mDisabledShowContext=");
+ pw.println(Integer.toHexString(mDisabledShowContext));
+ }
pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService);
if (mActiveSession != null) {
pw.println(" Active session:");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index bd043ac7655b..dfdd639b83bf 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -183,7 +183,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
}
}
- public boolean showLocked(Bundle args, int flags,
+ public boolean showLocked(Bundle args, int flags, int disabledContext,
IVoiceInteractionSessionShowCallback showCallback) {
if (mBound) {
if (!mFullyBound) {
@@ -200,15 +200,17 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
}
boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0
- && isScreenCaptureAllowed;
+ && isScreenCaptureAllowed
+ && (disabledContext&VoiceInteractionSession.SHOW_WITH_ASSIST) == 0;
boolean screenshotEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) != 0
- && isScreenCaptureAllowed;
+ && isScreenCaptureAllowed
+ && (disabledContext&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0;
mShowArgs = args;
mShowFlags = flags;
mHaveAssistData = false;
boolean needDisclosure = false;
- if ((flags& VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
+ if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
&& structureEnabled) {
@@ -226,7 +228,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
mAssistData = null;
}
mHaveScreenshot = false;
- if ((flags& VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
+ if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid,
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
&& screenshotEnabled) {
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index d18b86a754c4..79146f38c230 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -177,15 +177,19 @@ public class PhoneNumberUtils
phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
}
- final Cursor c = context.getContentResolver().query(uri, new String[] {
- phoneColumn
- }, null, null, null);
- if (c != null) {
- try {
+ Cursor c = null;
+ try {
+ c = context.getContentResolver().query(uri, new String[] { phoneColumn },
+ null, null, null);
+ if (c != null) {
if (c.moveToFirst()) {
number = c.getString(c.getColumnIndex(phoneColumn));
}
- } finally {
+ }
+ } catch (RuntimeException e) {
+ Rlog.e(LOG_TAG, "Error getting phone number.", e);
+ } finally {
+ if (c != null) {
c.close();
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f4a60643bcda..32b7383ff9a5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -21,12 +21,15 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.net.Uri;
import android.telephony.Rlog;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.os.RemoteException;
+import android.util.DisplayMetrics;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -248,6 +251,78 @@ public class SubscriptionManager {
public static final String MNC = "mnc";
/**
+ * TelephonyProvider column name for extreme threat in CB settings
+ * @hide
+ */
+ public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+ /**
+ * TelephonyProvider column name for severe threat in CB settings
+ *@hide
+ */
+ public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+ /**
+ * TelephonyProvider column name for amber alert in CB settings
+ *@hide
+ */
+ public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+ /**
+ * TelephonyProvider column name for emergency alert in CB settings
+ *@hide
+ */
+ public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+ /**
+ * TelephonyProvider column name for alert sound duration in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+ /**
+ * TelephonyProvider column name for alert reminder interval in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+ /**
+ * TelephonyProvider column name for enabling vibrate in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+ /**
+ * TelephonyProvider column name for enabling alert speech in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+ /**
+ * TelephonyProvider column name for ETWS test alert in CB settings
+ *@hide
+ */
+ public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+ /**
+ * TelephonyProvider column name for enable channel50 alert in CB settings
+ *@hide
+ */
+ public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+ /**
+ * TelephonyProvider column name for CMAS test alert in CB settings
+ *@hide
+ */
+ public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+
+ /**
+ * TelephonyProvider column name for Opt out dialog in CB settings
+ *@hide
+ */
+ public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*
@@ -1137,6 +1212,112 @@ public class SubscriptionManager {
}
/**
+ * Store properties associated with SubscriptionInfo in database
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in database associated with SubscriptionInfo
+ * @param propValue Value to store in DB for particular subId & column name
+ * @hide
+ */
+ public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.setSubscriptionProperty(subId, propKey, propValue);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ /**
+ * Store properties associated with SubscriptionInfo in database
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @return Value associated with subId and propKey column in database
+ * @hide
+ */
+ private static String getSubscriptionProperty(int subId, String propKey,
+ Context context) {
+ String resultValue = null;
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ resultValue = iSub.getSubscriptionProperty(subId, propKey,
+ context.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ return resultValue;
+ }
+
+ /**
+ * Returns boolean value corresponding to query result.
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @param defValue Default boolean value to be returned
+ * @return boolean result value to be returned
+ * @hide
+ */
+ public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
+ boolean defValue, Context context) {
+ String result = getSubscriptionProperty(subId, propKey, context);
+ if (result != null) {
+ try {
+ return Integer.parseInt(result) == 1;
+ } catch (NumberFormatException err) {
+ logd("getBooleanSubscriptionProperty NumberFormat exception");
+ }
+ }
+ return defValue;
+ }
+
+ /**
+ * Returns integer value corresponding to query result.
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @param defValue Default integer value to be returned
+ * @return integer result value to be returned
+ * @hide
+ */
+ public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
+ Context context) {
+ String result = getSubscriptionProperty(subId, propKey, context);
+ if (result != null) {
+ try {
+ return Integer.parseInt(result);
+ } catch (NumberFormatException err) {
+ logd("getBooleanSubscriptionProperty NumberFormat exception");
+ }
+ }
+ return defValue;
+ }
+
+ /**
+ * Returns the resources associated with Subscription.
+ * @param context Context object
+ * @param subId Subscription Id of Subscription who's resources are required
+ * @return Resources associated with Subscription.
+ * @hide
+ */
+ public static Resources getResourcesForSubId(Context context, int subId) {
+ final SubscriptionInfo subInfo =
+ SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
+
+ Configuration config = context.getResources().getConfiguration();
+ Configuration newConfig = new Configuration();
+ newConfig.setTo(config);
+ if (subInfo != null) {
+ newConfig.mcc = subInfo.getMcc();
+ newConfig.mnc = subInfo.getMnc();
+ }
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ DisplayMetrics newMetrics = new DisplayMetrics();
+ newMetrics.setTo(metrics);
+ return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+ }
+
+ /**
* @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
* and the SIM providing the subscription is present in a slot and in "LOADED" state.
* @hide
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 5cd5d4e8f97d..be7e7029115b 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -282,10 +283,17 @@ public class CallerInfo {
* number. The returned CallerInfo is null if no number is supplied.
*/
public static CallerInfo getCallerInfo(Context context, Uri contactRef) {
-
- return getCallerInfo(context, contactRef,
- CallerInfoAsyncQuery.getCurrentProfileContentResolver(context)
- .query(contactRef, null, null, null, null));
+ CallerInfo info = null;
+ ContentResolver cr = CallerInfoAsyncQuery.getCurrentProfileContentResolver(context);
+ if (cr != null) {
+ try {
+ info = getCallerInfo(context, contactRef,
+ cr.query(contactRef, null, null, null, null));
+ } catch (RuntimeException re) {
+ Rlog.e(TAG, "Error getting caller info.", re);
+ }
+ }
+ return info;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 0555121aa709..f6aef0859e90 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -172,6 +172,10 @@ interface ISub {
int[] getActiveSubIdList();
+ void setSubscriptionProperty(int subId, String propKey, String propValue);
+
+ String getSubscriptionProperty(int subId, String propKey, String callingPackage);
+
/**
* Get the SIM state for the slot idx
* @return SIM state as the ordinal of IccCardConstants.State
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
index 610f30b1bfcb..dc4e31bc0035 100644
--- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -31,33 +31,56 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
- <LinearLayout android:id="@+id/top_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:orientation="horizontal"
- android:background="#ffffffff"
- android:elevation="8dp"
- >
- <ImageView android:id="@+id/screenshot"
- android:layout_width="wrap_content"
- android:layout_height="46dp"
- android:adjustViewBounds="true" />
- <View android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
- <Button android:id="@+id/do_tree"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/tree" />
- <Button android:id="@+id/do_text"
- android:layout_width="wrap_content"
+ android:layout_gravity="top"
+ android:orientation="vertical"
+ android:background="#ffffffff"
+ android:elevation="8dp"
+ >
+ <LinearLayout android:id="@+id/top_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/text" />
- <Button android:id="@+id/start"
- android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ >
+ <ImageView android:id="@+id/screenshot"
+ android:layout_width="wrap_content"
+ android:layout_height="46dp"
+ android:adjustViewBounds="true" />
+ <View android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+ <CheckBox android:id="@+id/show_options"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/do_tree"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/tree" />
+ <Button android:id="@+id/do_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text" />
+ <Button android:id="@+id/start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/options"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/start" />
+ android:orientation="vertical"
+ >
+ <CheckBox android:id="@+id/disallow_structure"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disallow context" />
+ <CheckBox android:id="@+id/disallow_screenshot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disallow screenshot" />
+ </LinearLayout>
</LinearLayout>
<LinearLayout android:id="@+id/bottom_content"
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index a6585ba896fe..8796c9f75037 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -29,6 +29,7 @@ import android.service.voice.VoiceInteractionSession;
import android.util.Log;
import android.view.View;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
@@ -45,6 +46,10 @@ public class MainInteractionSession extends VoiceInteractionSession
Button mTreeButton;
Button mTextButton;
Button mStartButton;
+ CheckBox mOptionsCheck;
+ View mOptionsContainer;
+ CheckBox mDisallowAssist;
+ CheckBox mDisallowScreenshot;
ImageView mScreenshot;
ImageView mFullScreenshot;
Button mConfirmButton;
@@ -122,15 +127,34 @@ public class MainInteractionSession extends VoiceInteractionSession
mScreenshot = (ImageView)mContentView.findViewById(R.id.screenshot);
mScreenshot.setOnClickListener(this);
mFullScreenshot = (ImageView)mContentView.findViewById(R.id.full_screenshot);
+ mOptionsCheck = (CheckBox)mContentView.findViewById(R.id.show_options);
+ mOptionsCheck.setOnClickListener(this);
+ mOptionsContainer = mContentView.findViewById(R.id.options);
+ mDisallowAssist = (CheckBox)mContentView.findViewById(R.id.disallow_structure);
+ mDisallowAssist.setOnClickListener(this);
+ mDisallowScreenshot = (CheckBox)mContentView.findViewById(R.id.disallow_screenshot);
+ mDisallowScreenshot.setOnClickListener(this);
mConfirmButton = (Button)mContentView.findViewById(R.id.confirm);
mConfirmButton.setOnClickListener(this);
mCompleteButton = (Button)mContentView.findViewById(R.id.complete);
mCompleteButton.setOnClickListener(this);
mAbortButton = (Button)mContentView.findViewById(R.id.abort);
mAbortButton.setOnClickListener(this);
+ refreshOptions();
return mContentView;
}
+ void refreshOptions() {
+ if (mOptionsCheck.isChecked()) {
+ mOptionsContainer.setVisibility(View.VISIBLE);
+ int flags = getDisabledShowContext();
+ mDisallowAssist.setChecked((flags & SHOW_WITH_ASSIST) != 0);
+ mDisallowScreenshot.setChecked((flags & SHOW_WITH_SCREENSHOT) != 0);
+ } else {
+ mOptionsContainer.setVisibility(View.GONE);
+ }
+ }
+
public void onHandleAssist(Bundle assistBundle) {
}
@@ -202,6 +226,24 @@ public class MainInteractionSession extends VoiceInteractionSession
if (mAssistVisualizer != null) {
mAssistVisualizer.logText();
}
+ } else if (v == mOptionsCheck) {
+ refreshOptions();
+ } else if (v == mDisallowAssist) {
+ int flags = getDisabledShowContext();
+ if (mDisallowAssist.isChecked()) {
+ flags |= SHOW_WITH_ASSIST;
+ } else {
+ flags &= ~SHOW_WITH_ASSIST;
+ }
+ setDisabledShowContext(flags);
+ } else if (v == mDisallowScreenshot) {
+ int flags = getDisabledShowContext();
+ if (mDisallowScreenshot.isChecked()) {
+ flags |= SHOW_WITH_SCREENSHOT;
+ } else {
+ flags &= ~SHOW_WITH_SCREENSHOT;
+ }
+ setDisabledShowContext(flags);
} else if (v == mStartButton) {
mState = STATE_LAUNCHING;
updateState();
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index 2487e1ca9466..b0d6b399eaaa 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -103,6 +103,14 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
}
};
mInteractor.submitRequest(mCurrentRequest, REQUEST_CONFIRM);
+ String[] cmds = new String[] {
+ "com.android.test.voiceinteraction.COMMAND",
+ "com.example.foo.bar"
+ };
+ boolean sup[] = mInteractor.supportsCommands(cmds);
+ for (int i=0; i<cmds.length; i++) {
+ mLog.append(cmds[i] + ": " + (sup[i] ? "SUPPORTED" : "NOT SUPPORTED") + "\n");
+ }
} else {
Log.i(TAG, "Restarting with active confirmation: " + mCurrentRequest);
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 20b6e416dc6b..1e33e3ab2090 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -25,6 +25,7 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.util.ReflectionUtils;
@@ -33,10 +34,13 @@ import com.android.util.Pair;
import org.xmlpull.v1.XmlPullParser;
+import android.annotation.NonNull;
import android.content.Context;
import android.util.AttributeSet;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
import static com.android.layoutlib.bridge.android.BridgeContext.getBaseContext;
@@ -48,6 +52,7 @@ public final class BridgeInflater extends LayoutInflater {
private final LayoutlibCallback mLayoutlibCallback;
private boolean mIsInMerge = false;
private ResourceReference mResourceReference;
+ private Map<View, String> mOpenDrawerLayouts;
/**
* List of class prefixes which are tried first by default.
@@ -256,7 +261,14 @@ public final class BridgeInflater extends LayoutInflater {
resourceId = 0;
}
RecyclerViewUtil.setAdapter(view, bc, mLayoutlibCallback, resourceId);
+ } else if (ReflectionUtils.isInstanceOf(view, DrawerLayoutUtil.CN_DRAWER_LAYOUT)) {
+ String attrVal = attrs.getAttributeValue(BridgeConstants.NS_TOOLS_URI,
+ BridgeConstants.ATTR_OPEN_DRAWER);
+ if (attrVal != null) {
+ getDrawerLayoutMap().put(view, attrVal);
+ }
}
+
}
}
@@ -312,4 +324,28 @@ public final class BridgeInflater extends LayoutInflater {
return viewKey;
}
+
+ public void postInflateProcess(View view) {
+ if (mOpenDrawerLayouts != null) {
+ String gravity = mOpenDrawerLayouts.get(view);
+ if (gravity != null) {
+ DrawerLayoutUtil.openDrawer(view, gravity);
+ }
+ mOpenDrawerLayouts.remove(view);
+ }
+ }
+
+ @NonNull
+ private Map<View, String> getDrawerLayoutMap() {
+ if (mOpenDrawerLayouts == null) {
+ mOpenDrawerLayouts = new HashMap<View, String>(4);
+ }
+ return mOpenDrawerLayouts;
+ }
+
+ public void onDoneInflation() {
+ if (mOpenDrawerLayouts != null) {
+ mOpenDrawerLayouts.clear();
+ }
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 661c08b98e81..62287669577c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -50,6 +50,9 @@ public class BridgeConstants {
public final static String FILL_PARENT = "fill_parent";
public final static String WRAP_CONTENT = "wrap_content";
+ // Should be kept in sync with LayoutMetadata.KEY_LV_ITEM in tools/adt/idea
/** Attribute in the tools namespace used to specify layout manager for RecyclerView. */
- public static final String ATTR_LIST_ITEM = "list_item";
+ @SuppressWarnings("SpellCheckingInspection")
+ public static final String ATTR_LIST_ITEM = "listitem";
+ public static final String ATTR_OPEN_DRAWER = "openDrawer";
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 085df859a963..895f9c9eaeac 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -137,7 +137,7 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
- public void wakeUp(long time) throws RemoteException {
+ public void wakeUp(long time, String reason, String opPackageName) throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
new file mode 100644
index 000000000000..40d3811cbdf7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
@@ -0,0 +1,63 @@
+/*
+ * 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.layoutlib.bridge.android.support;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+
+import android.annotation.Nullable;
+import android.view.View;
+
+import static android.view.Gravity.END;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.START;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+
+public class DrawerLayoutUtil {
+
+ public static final String CN_DRAWER_LAYOUT = "android.support.v4.widget.DrawerLayout";
+
+ public static void openDrawer(View drawerLayout, @Nullable String drawerGravity) {
+ int gravity = -1;
+ if ("left".equals(drawerGravity)) {
+ gravity = LEFT;
+ } else if ("right".equals(drawerGravity)) {
+ gravity = RIGHT;
+ } else if ("start".equals(drawerGravity)) {
+ gravity = START;
+ } else if ("end".equals(drawerGravity)) {
+ gravity = END;
+ }
+ if (gravity > 0) {
+ openDrawer(drawerLayout, gravity);
+ }
+ }
+
+ private static void openDrawer(View drawerLayout, int gravity) {
+ try {
+ invoke(getMethod(drawerLayout.getClass(), "openDrawer", int.class), drawerLayout,
+ gravity);
+ } catch (ReflectionException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to open navigation drawer",
+ getCause(e), null);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index 4182cd92016c..d14c80b90890 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -21,6 +21,7 @@ import com.android.ide.common.rendering.api.LayoutlibCallback;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.util.ReflectionUtils;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,6 +31,7 @@ import android.view.View;
import java.lang.reflect.Method;
import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
@@ -70,11 +72,6 @@ public class RecyclerViewUtil {
}
}
- private static Throwable getCause(Throwable throwable) {
- Throwable cause = throwable.getCause();
- return cause == null ? throwable : cause;
- }
-
private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
@NonNull LayoutlibCallback callback) throws ReflectionException {
if (getLayoutManager(recyclerView) == null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 72e97ad3538e..23df3f1c4267 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -423,6 +423,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// post-inflate process. For now this supports TabHost/TabWidget
postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
+ mInflater.onDoneInflation();
setActiveToolbar(view, context, params);
@@ -1342,6 +1343,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
} else if (view instanceof ViewGroup) {
+ mInflater.postInflateProcess(view);
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
for (int c = 0; c < count; c++) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
index b78b613bf280..7ce27b6a55fa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
@@ -27,7 +27,7 @@ import java.lang.reflect.Method;
*/
public class ReflectionUtils {
- @Nullable
+ @NonNull
public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
@Nullable Class<?>... params) throws ReflectionException {
try {
@@ -67,6 +67,12 @@ public class ReflectionUtils {
return false;
}
+ @NonNull
+ public static Throwable getCause(@NonNull Throwable throwable) {
+ Throwable cause = throwable.getCause();
+ return cause == null ? throwable : cause;
+ }
+
/**
* Wraps all reflection related exceptions. Created since ReflectiveOperationException was
* introduced in 1.7 and we are still on 1.6