Merge "Import translations. DO NOT MERGE" into mnc-dev
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index da8586c..2754f2d 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 @@
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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bf3bfae..849253b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -233,8 +233,10 @@
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 @@
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 @@
OPSTR_READ_CELL_BROADCASTS,
OPSTR_MOCK_LOCATION,
OPSTR_READ_EXTERNAL_STORAGE,
- OPSTR_WRITE_EXTERNAL_STORAGE
+ OPSTR_WRITE_EXTERNAL_STORAGE,
+ null,
};
/**
@@ -528,8 +532,9 @@
"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 @@
null,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ null, // no permission for turning the screen on
};
/**
@@ -666,7 +672,8 @@
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 @@
false, // READ_CELL_BROADCASTS
false, // MOCK_LOCATION
false, // READ_EXTERNAL_STORAGE
- false // WRITE_EXTERNAL_STORAGE
+ false, // WRITE_EXTERNAL_STORAGE
+ false, // TURN_ON_SCREEN
};
/**
@@ -801,7 +809,8 @@
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 @@
false,
false,
false,
- false
+ false,
+ false,
};
/**
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 0fe112c..80c7b1a 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -19,6 +19,8 @@
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 @@
/* 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 f58b9d6..c88f213 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 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 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 @@
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 0000000..b7a7920
--- /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 0000000..c9a4e9b
--- /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 0000000..9a7e468
--- /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 0000000..5c0e81a
--- /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 452e4d5..ecb7f5a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1195,9 +1195,11 @@
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 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 804d3d0..0f37ac7 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -37,7 +37,7 @@
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 6ef1cd0..9a1a03e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -658,7 +658,17 @@
*/
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/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index 5f5b079..eeb340b 100644
--- a/core/java/android/service/dreams/Sandman.java
+++ b/core/java/android/service/dreams/Sandman.java
@@ -92,7 +92,8 @@
// 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/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 6f0cec6..3cddbf6 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -83,6 +83,7 @@
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/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ae2cbad..60f47d6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3122,6 +3122,13 @@
}
}
+ 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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d3117b9..062ae27 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/values-az-rAZ-watch/strings.xml b/core/res/res/values-az-rAZ-watch/strings.xml
new file mode 100644
index 0000000..7e4a762
--- /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 cc23637..960bc56 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 0000000..32d21c5
--- /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 f357bb6..3994bba 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 f24bed0..0a9d58d 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 764b792..a94680d 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/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 6a72d83..e67c554 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/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index c541bca..a57bcc6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -720,14 +720,15 @@
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/SettingsProvider/res/values-pt-rPT/strings.xml b/packages/SettingsProvider/res/values-pt-rPT/strings.xml
index 6bd62e3..c7dc9e6 100644
--- a/packages/SettingsProvider/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsProvider/res/values-pt-rPT/strings.xml
@@ -19,5 +19,5 @@
<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="4567566098528588863">"Armazenamento de Definições"</string>
+ <string name="app_label" msgid="4567566098528588863">"Armazenamento de definições"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-vi/strings.xml b/packages/SettingsProvider/res/values-vi/strings.xml
index 504479d..015fbfd 100644
--- a/packages/SettingsProvider/res/values-vi/strings.xml
+++ b/packages/SettingsProvider/res/values-vi/strings.xml
@@ -19,5 +19,5 @@
<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="4567566098528588863">"Lưu trữ cài đặt"</string>
+ <string name="app_label" msgid="4567566098528588863">"Lưu trữ bộ nhớ"</string>
</resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index 6278650..d83b516 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -215,6 +215,7 @@
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/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 155f5ea..3210a24 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/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 88aa071..1e78f66 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 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/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index 41ce25d..5388f10 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -134,7 +134,8 @@
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/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 13b75ab..4b0b924 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 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 458928f..8813a61 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 @@
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 4d8d105..a71dfcd 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -565,7 +565,8 @@
// 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 c37f619..cfc5f7d 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 @@
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9e41f70..978ed51 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -753,7 +753,8 @@
synchronized (mLock) {
if (shouldEnableWakeGestureLp()) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
- wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture);
+ wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
+ "android.policy:GESTURE");
}
}
}
@@ -4691,7 +4692,8 @@
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 +4715,8 @@
} 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 +4895,7 @@
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
if (isWakeKey) {
- wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
+ wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
@@ -5123,7 +5126,7 @@
}
if (isWakeKey) {
- wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
+ wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
@@ -5184,7 +5187,8 @@
@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 +5201,8 @@
// 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 +5498,10 @@
}
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 +5512,7 @@
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 d21c6d2..c5ad7fe 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 @@
}
/**
+ * 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 3f59755..88476ce 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
@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 @@
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 ec566bc..05c111c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10307,7 +10307,7 @@
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 638783d..31763e7 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 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 @@
//
// 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 9a04e8b..ae17fde3 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.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 @@
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 81b4857..653cbd8 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.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 @@
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 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 f5f2b07..6300a9a 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.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 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 0000000..52abcfe
--- /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 c8b42262..f93a2ef 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.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 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 @@
private UsbDeviceManager mDeviceManager;
private UsbHostManager mHostManager;
+ private UsbPortManager mPortManager;
private final UsbAlsaManager mAlsaManager;
private final Object mLock = new Object();
@@ -110,6 +115,9 @@
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 @@
if (mHostManager != null) {
mHostManager.systemReady();
}
+ if (mPortManager != null) {
+ mPortManager.systemReady();
+ }
}
public void bootCompleted() {
@@ -346,29 +357,258 @@
}
@Override
+ public UsbPort[] getPorts() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mPortManager != null ? mPortManager.getPorts() : null;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @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);
+ }
+ }
+
+ @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, " ");
-
- pw.println("USB Manager State:");
- if (mDeviceManager != null) {
- mDeviceManager.dump(fd, pw);
- }
- if (mHostManager != null) {
- mHostManager.dump(fd, pw);
- }
- 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);
+ 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 2331a8b..2cf42f0 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 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 @@
}
}
- 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/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index d18b86a..79146f3 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -177,15 +177,19 @@
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/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 5cd5d4e..be7e702 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 @@
* 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/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 085df85..895f9c9 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 @@
}
@Override
- public void wakeUp(long time) throws RemoteException {
+ public void wakeUp(long time, String reason, String opPackageName) throws RemoteException {
// pass for now.
}