Merge "API support for reporting of changes to call features. (eg VoLTE, VoWIFI, etc)"
diff --git a/api/current.txt b/api/current.txt
index 39f67f7..a39bc79 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23223,6 +23223,7 @@
field public static final android.net.Uri AUTHORITY_URI;
field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
field public static final java.lang.String DEFERRED_SNIPPETING = "deferred_snippeting";
+ field public static final java.lang.String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
field public static final java.lang.String DIRECTORY_PARAM_KEY = "directory";
field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
field public static final java.lang.String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
@@ -23888,11 +23889,10 @@
field public static final android.net.Uri PROFILE_CONTENT_URI;
}
- public static class ContactsContract.SearchSnippetColumns {
- ctor public ContactsContract.SearchSnippetColumns();
+ public static class ContactsContract.SearchSnippets {
+ ctor public ContactsContract.SearchSnippets();
field public static final java.lang.String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
field public static final java.lang.String SNIPPET = "snippet";
- field public static final java.lang.String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
}
public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
@@ -27565,12 +27565,12 @@
public abstract class CallVideoClient {
ctor protected CallVideoClient();
- method public abstract void onCallSessionEvent(int);
- method public abstract void onCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities);
+ method public abstract void onHandleCallSessionEvent(int);
+ method public abstract void onHandleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities);
method public abstract void onReceiveSessionModifyRequest(android.telecomm.VideoCallProfile);
method public abstract void onReceiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
method public abstract void onUpdateCallDataUsage(int);
- method public abstract void onUpdatedPeerDimensions(int, int);
+ method public abstract void onUpdatePeerDimensions(int, int);
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
field public static final int SESSION_EVENT_TX_START = 3; // 0x3
@@ -27582,16 +27582,17 @@
public abstract class CallVideoProvider {
ctor protected CallVideoProvider();
- method public abstract void requestCallDataUsage();
- method public abstract void requestCameraCapabilities();
- method public abstract void sendSessionModifyRequest(android.telecomm.VideoCallProfile);
- method public abstract void sendSessionModifyResponse(android.telecomm.VideoCallProfile);
- method public abstract void setCamera(java.lang.String);
- method public abstract void setDeviceOrientation(int);
- method public abstract void setDisplaySurface(android.view.Surface);
- method public abstract void setPauseImage(java.lang.String);
- method public abstract void setPreviewSurface(android.view.Surface);
- method public abstract void setZoom(float);
+ method public abstract void onRequestCallDataUsage();
+ method public abstract void onRequestCameraCapabilities();
+ method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile);
+ method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile);
+ method public abstract void onSetCallVideoClient(android.telecomm.RemoteCallVideoClient);
+ method public abstract void onSetCamera(java.lang.String);
+ method public abstract void onSetDeviceOrientation(int);
+ method public abstract void onSetDisplaySurface(android.view.Surface);
+ method public abstract void onSetPauseImage(java.lang.String);
+ method public abstract void onSetPreviewSurface(android.view.Surface);
+ method public abstract void onSetZoom(float);
}
public abstract class Connection {
@@ -27777,9 +27778,29 @@
method protected abstract void updateCall(android.telecomm.InCallCall);
}
+ public class RemoteCallVideoClient implements android.os.IBinder.DeathRecipient {
+ method public void binderDied();
+ method public void handleCallSessionEvent(int) throws android.os.RemoteException;
+ method public void handleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities) throws android.os.RemoteException;
+ method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+ method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+ method public void updateCallDataUsage(int) throws android.os.RemoteException;
+ method public void updatePeerDimensions(int, int) throws android.os.RemoteException;
+ }
+
public class RemoteCallVideoProvider implements android.os.IBinder.DeathRecipient {
method public void binderDied();
+ method public void onSetPauseImage(java.lang.String) throws android.os.RemoteException;
+ method public void requestCallDataUsage() throws android.os.RemoteException;
+ method public void requestCameraCapabilities() throws android.os.RemoteException;
+ method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+ method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+ method public void setCallVideoClient(android.telecomm.CallVideoClient) throws android.os.RemoteException;
method public void setCamera(java.lang.String) throws android.os.RemoteException;
+ method public void setDeviceOrientation(int) throws android.os.RemoteException;
+ method public void setDisplaySurface(android.view.Surface) throws android.os.RemoteException;
+ method public void setPreviewSurface(android.view.Surface) throws android.os.RemoteException;
+ method public void setZoom(float) throws android.os.RemoteException;
}
public final class RemoteConnection {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index d33b14a..a8f6539 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -45,6 +45,7 @@
private static final String TAG = "EnterTransitionCoordinator";
private static final long MAX_WAIT_MS = 1000;
+ private static final int MIN_ANIMATION_FRAMES = 2;
private boolean mSharedElementTransitionStarted;
private Activity mActivity;
@@ -280,9 +281,21 @@
setOriginalImageViewState(originalImageViewState);
if (mResultReceiver != null) {
- mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+ // We can't trust that the view will disappear on the same frame that the shared
+ // element appears here. Assure that we get at least 2 frames for double-buffering.
+ getDecor().postOnAnimation(new Runnable() {
+ int mAnimations;
+ @Override
+ public void run() {
+ if (mAnimations++ < MIN_ANIMATION_FRAMES) {
+ getDecor().postOnAnimation(this);
+ } else {
+ mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+ mResultReceiver = null; // all done sending messages.
+ }
+ }
+ });
}
- mResultReceiver = null; // all done sending messages.
}
@Override
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 49f2a5d..ba34184 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -29,6 +29,7 @@
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
@@ -65,8 +66,6 @@
private Bundle mExitSharedElementBundle;
- private ArrayList<View> mSharedElementSnapshots;
-
public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
super(activity.getWindow(), names, getListener(activity, isReturning),
@@ -131,17 +130,14 @@
Transition transition = getSharedElementExitTransition();
final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
mSharedElementNames);
- mSharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames);
transition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
- setViewVisibility(mSharedElements, View.INVISIBLE);
- ViewGroupOverlay overlay = getDecor().getOverlay();
- if (mSharedElementSnapshots != null) {
- for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
- overlay.add(mSharedElementSnapshots.get(i));
- }
+ int count = mSharedElements.size();
+ for (int i = 0; i < count; i++) {
+ View sharedElement = mSharedElements.get(i);
+ ((ViewGroup)sharedElement.getParent()).suppressLayout(true);
}
}
});
@@ -158,28 +154,10 @@
getDecor().invalidate();
}
- private static ArrayList<View> copySnapshots(ArrayList<View> snapshots) {
- ArrayList<View> copy = new ArrayList<View>(snapshots.size());
- for (int i = 0; i < snapshots.size(); i++) {
- View view = snapshots.get(i);
- View viewCopy = new View(view.getContext());
- viewCopy.setBackground(view.getBackground());
- copy.add(viewCopy);
- }
- return copy;
- }
-
private void hideSharedElements() {
if (!mIsHidden) {
setViewVisibility(mSharedElements, View.INVISIBLE);
}
- if (mSharedElementSnapshots != null) {
- ViewGroupOverlay overlay = getDecor().getOverlay();
- for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
- overlay.remove(mSharedElementSnapshots.get(i));
- }
- mSharedElementSnapshots = null;
- }
finishIfNecessary();
}
@@ -360,7 +338,8 @@
}
private void finishIfNecessary() {
- if (mIsReturning && mExitNotified && mActivity != null && mSharedElementSnapshots == null) {
+ if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
+ mSharedElements.get(0).getVisibility() == View.INVISIBLE)) {
finish();
}
if (!mIsReturning && mExitNotified) {
@@ -382,7 +361,6 @@
mBackgroundAnimator = null;
}
mExitSharedElementBundle = null;
- mSharedElementSnapshots = null;
clearState();
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 64d80a0..a94bc41 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -306,6 +306,11 @@
public static final String ACTION_UUID =
"android.bluetooth.device.action.UUID";
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_MAS_INSTANCE =
+ "android.bluetooth.device.action.MAS_INSTANCE";
+
/**
* Broadcast Action: Indicates a failure to retrieve the name of a remote
* device.
@@ -522,14 +527,17 @@
* Prefer BR/EDR transport for GATT connections to remote dual-mode devices
* @hide
*/
- public static final int TRANSPORT_BREDR = 1;
+ public static final int TRANSPORT_BREDR = 1;
/**
* Prefer LE transport for GATT connections to remote dual-mode devices
* @hide
*/
- public static final int TRANSPORT_LE = 2;
+ public static final int TRANSPORT_LE = 2;
+ /** @hide */
+ public static final String EXTRA_MAS_INSTANCE =
+ "android.bluetooth.device.extra.MAS_INSTANCE";
/**
* Lazy initialization. Guaranteed final after first object constructed, or
@@ -995,6 +1003,18 @@
return false;
}
+ /** @hide */
+ public boolean fetchMasInstances() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot query remote device for MAS instances");
+ return false;
+ }
+ try {
+ return sService.fetchRemoteMasInstances(this);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
/** @hide */
public int getServiceChannel(ParcelUuid uuid) {
//TODO(BT)
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 2e993c9d..fbbc2f7 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -32,12 +32,12 @@
* Public API for the Bluetooth GATT Profile server role.
*
* <p>This class provides Bluetooth GATT server role functionality,
- * allowing applications to create and advertise Bluetooth Smart services
- * and characteristics.
+ * allowing applications to create Bluetooth Smart services and
+ * characteristics.
*
* <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
- * via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
- * BluetoothGatt proxy object.
+ * via IPC. Use {@link BluetoothManager#openGattServer} to get an instance
+ * of this class.
*/
public final class BluetoothGattServer implements BluetoothProfile {
private static final String TAG = "BluetoothGattServer";
@@ -545,7 +545,7 @@
/**
* Add a service to the list of services to be hosted.
*
- * <p>Once a service has been addded to the the list, the service and it's
+ * <p>Once a service has been addded to the the list, the service and its
* included characteristics will be provided by the local device.
*
* <p>If the local device has already exposed services when this function
diff --git a/core/java/android/bluetooth/BluetoothMasInstance.java b/core/java/android/bluetooth/BluetoothMasInstance.java
new file mode 100644
index 0000000..4459e2c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothMasInstance.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class BluetoothMasInstance implements Parcelable {
+ private final int mId;
+ private final String mName;
+ private final int mChannel;
+ private final int mMsgTypes;
+
+ public BluetoothMasInstance(int id, String name, int channel, int msgTypes) {
+ mId = id;
+ mName = name;
+ mChannel = channel;
+ mMsgTypes = msgTypes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothMasInstance) {
+ return mId == ((BluetoothMasInstance)o).mId;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mId + (mChannel << 8) + (mMsgTypes << 16);
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(mId) + ":" + mName + ":" + mChannel + ":" +
+ Integer.toHexString(mMsgTypes);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothMasInstance> CREATOR =
+ new Parcelable.Creator<BluetoothMasInstance>() {
+ public BluetoothMasInstance createFromParcel(Parcel in) {
+ return new BluetoothMasInstance(in.readInt(), in.readString(),
+ in.readInt(), in.readInt());
+ }
+ public BluetoothMasInstance[] newArray(int size) {
+ return new BluetoothMasInstance[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeString(mName);
+ out.writeInt(mChannel);
+ out.writeInt(mMsgTypes);
+ }
+
+ public static final class MessageType {
+ public static final int EMAIL = 0x01;
+ public static final int SMS_GSM = 0x02;
+ public static final int SMS_CDMA = 0x04;
+ public static final int MMS = 0x08;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public int getChannel() {
+ return mChannel;
+ }
+
+ public int getMsgTypes() {
+ return mMsgTypes;
+ }
+
+ public boolean msgSupported(int msg) {
+ return (mMsgTypes & msg) != 0;
+ }
+}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a45c6b8..df6037e 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -67,6 +67,7 @@
int getRemoteClass(in BluetoothDevice device);
ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
boolean fetchRemoteUuids(in BluetoothDevice device);
+ boolean fetchRemoteMasInstances(in BluetoothDevice device);
boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index df6057e..1129c9e 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -31,11 +31,15 @@
/** Control UID policies. */
void setUidPolicy(int uid, int policy);
+ void addUidPolicy(int uid, int policy);
+ void removeUidPolicy(int uid, int policy);
int getUidPolicy(int uid);
int[] getUidsWithPolicy(int policy);
boolean isUidForeground(int uid);
+ int[] getPowerSaveAppIdWhitelist();
+
void registerListener(INetworkPolicyListener listener);
void unregisterListener(INetworkPolicyListener listener);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2cd1f9b..a8e7757 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -45,6 +45,8 @@
public static final int POLICY_NONE = 0x0;
/** Reject network usage on metered networks when application in background. */
public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
+ /** Allow network use (metered or not) in the background in battery save mode. */
+ public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
/** All network traffic should be allowed. */
public static final int RULE_ALLOW_ALL = 0x0;
@@ -76,7 +78,7 @@
* Set policy flags for specific UID.
*
* @param policy {@link #POLICY_NONE} or combination of flags like
- * {@link #POLICY_REJECT_METERED_BACKGROUND}.
+ * {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
*/
public void setUidPolicy(int uid, int policy) {
try {
@@ -85,6 +87,30 @@
}
}
+ /**
+ * Add policy flags for specific UID. The given policy bits will be set for
+ * the uid. Policy flags may be either
+ * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+ */
+ public void addUidPolicy(int uid, int policy) {
+ try {
+ mService.addUidPolicy(uid, policy);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Clear/remove policy flags for specific UID. The given policy bits will be set for
+ * the uid. Policy flags may be either
+ * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+ */
+ public void removeUidPolicy(int uid, int policy) {
+ try {
+ mService.removeUidPolicy(uid, policy);
+ } catch (RemoteException e) {
+ }
+ }
+
public int getUidPolicy(int uid) {
try {
return mService.getUidPolicy(uid);
@@ -101,6 +127,14 @@
}
}
+ public int[] getPowerSaveAppIdWhitelist() {
+ try {
+ return mService.getPowerSaveAppIdWhitelist();
+ } catch (RemoteException e) {
+ return new int[0];
+ }
+ }
+
public void registerListener(INetworkPolicyListener listener) {
try {
mService.registerListener(listener);
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index cabda5d..34568c2 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -16,7 +16,7 @@
* The AidGroup class represents a group of Application Identifiers (AIDs).
*
* <p>An instance of this object can be used with
- * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)}
+ * {@link CardEmulation#registerAidsForService(android.content.ComponentName, String, java.util.List)}
* to tell the OS which AIDs are handled by your HCE- or SE-based service.
*
* <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
@@ -50,6 +50,11 @@
if (aids.size() > MAX_NUM_AIDS) {
throw new IllegalArgumentException("Too many AIDs in AID group.");
}
+ for (String aid : aids) {
+ if (!ApduServiceInfo.isValidAid(aid)) {
+ throw new IllegalArgumentException("AID " + aid + " is not a valid AID.");
+ }
+ }
if (isValidCategory(category)) {
this.category = category;
} else {
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index f379ee8..930cf11 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -351,20 +351,37 @@
}
}
+ /**
+ * A valid AID according to ISO/IEC 7816-4:
+ * <ul>
+ * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
+ * <li>Consist of only hex characters
+ * <li>Additionally, we allow an asterisk at the end, to indicate
+ * a prefix
+ * </ul>
+ */
static boolean isValidAid(String aid) {
if (aid == null)
return false;
- int aidLength = aid.length();
- if (aidLength == 0 || (aidLength % 2) != 0) {
- Log.e(TAG, "AID " + aid + " is not correctly formatted.");
+ // If a prefix AID, the total length must be odd (even # of AID chars + '*')
+ if (aid.endsWith("*") && ((aid.length() % 2) == 0)) {
+ Log.e(TAG, "AID " + aid + " is not a valid AID.");
return false;
}
- // Minimum AID length is 5 bytes, 10 hex chars
- if (aidLength < 10) {
- Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+
+ // If not a prefix AID, the total length must be even (even # of AID chars)
+ if (!aid.endsWith("*") && ((aid.length() % 2) != 0)) {
+ Log.e(TAG, "AID " + aid + " is not a valid AID.");
return false;
}
+
+ // Verify hex characters
+ if (!aid.matches("[0-9A-Fa-f]{10,32}\\*?")) {
+ Log.e(TAG, "AID " + aid + " is not a valid AID.");
+ return false;
+ }
+
return true;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f7d2bfd..21d60c5 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -614,6 +614,7 @@
public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
public static final int STATE2_WIFI_RUNNING_FLAG = 1<<29;
public static final int STATE2_WIFI_ON_FLAG = 1<<28;
+ public static final int STATE2_FLASHLIGHT_FLAG = 1<<27;
public static final int MOST_INTERESTING_STATES2 =
STATE2_LOW_POWER_FLAG | STATE2_WIFI_ON_FLAG;
@@ -1235,6 +1236,7 @@
new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
new BitDescription(HistoryItem.STATE2_WIFI_ON_FLAG, "wifi", "W"),
+ new BitDescription(HistoryItem.STATE2_FLASHLIGHT_FLAG, "flashlight", "fl"),
new BitDescription(HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK,
HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT, "wifi_signal_strength", "Wss",
new String[] { "0", "1", "2", "3", "4" },
@@ -1370,6 +1372,22 @@
*/
public abstract int getBluetoothStateCount(int bluetoothState, int which);
+ /**
+ * Returns the time in microseconds that the flashlight has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getFlashlightOnTime(long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns the number of times that the flashlight has been turned on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getFlashlightOnCount(int which);
+
public static final int NETWORK_MOBILE_RX_DATA = 0;
public static final int NETWORK_MOBILE_TX_DATA = 1;
public static final int NETWORK_WIFI_RX_DATA = 2;
@@ -1965,6 +1983,9 @@
case SCREEN:
label="scrn";
break;
+ case FLASHLIGHT:
+ label="flashlight";
+ break;
case APP:
uid = bs.uidObj.getUid();
label = "uid";
@@ -2637,6 +2658,10 @@
pw.print(prefix); pw.print(" Screen: "); printmAh(pw, bs.value);
pw.println();
break;
+ case FLASHLIGHT:
+ pw.print(prefix); pw.print(" Flashlight: "); printmAh(pw, bs.value);
+ pw.println();
+ break;
case APP:
pw.print(prefix); pw.print(" Uid ");
UserHandle.formatUid(pw, bs.uidObj.getUid());
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b839613..2f061f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -36,6 +36,7 @@
import android.database.DatabaseUtils;
import android.graphics.Rect;
import android.net.Uri;
+import android.net.Uri.Builder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.DisplayMetrics;
@@ -171,13 +172,16 @@
* A key to a boolean in the "extras" bundle of the cursor.
* The boolean indicates that the provider did not create a snippet and that the client asking
* for the snippet should do it (true means the snippeting was deferred to the client).
+ *
+ * @see SearchSnippets
*/
public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
/**
- * Key to retrieve the original query on the client side.
+ * Key to retrieve the original deferred snippeting from the cursor on the client side.
*
- * @hide
+ * @see SearchSnippets
+ * @see #DEFERRED_SNIPPETING
*/
public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
@@ -5089,42 +5093,75 @@
/**
* Additional column returned by
* {@link ContactsContract.Contacts#CONTENT_FILTER_URI Contacts.CONTENT_FILTER_URI} explaining
- * why the filter matched the contact. Specifically, it contains the data elements that
- * matched the query. The overall number of words in the snippet can be capped.
+ * why the filter matched the contact. This column will contain extracts from the contact's
+ * constituent {@link Data Data} items, formatted in a way that indicates the section of the
+ * snippet that matched the filter.
+ *
+ * <p>
+ * The following example searches for all contacts that match the query "presi" and requests
+ * the snippet column as well.
+ * <pre>
+ * Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon();
+ * builder.appendPath("presi");
+ * // Defer snippeting to the client side if possible, for performance reasons.
+ * builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY,"1");
+ *
+ * Cursor cursor = getContentResolver().query(builder.build());
+ *
+ * Bundle extras = cursor.getExtras();
+ * if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
+ * // Do our own snippet formatting.
+ * // For a contact with the email address (president@organization.com), the snippet
+ * // column will contain the string "president@organization.com".
+ * } else {
+ * // The snippet has already been pre-formatted, we can display it as is.
+ * // For a contact with the email address (president@organization.com), the snippet
+ * // column will contain the string "[presi]dent@organization.com".
+ * }
+ * </pre>
+ * </p>
*/
- public static class SearchSnippetColumns {
+ public static class SearchSnippets {
/**
- * The search snippet constructed according to the SQLite rules, see
- * http://www.sqlite.org/fts3.html#snippet
+ * The search snippet constructed by SQLite snippeting functionality.
* <p>
- * The snippet may contain (parts of) several data elements comprising
- * the contact.
+ * The snippet may contain (parts of) several data elements belonging to the contact,
+ * with the matching parts optionally surrounded by special characters that indicate the
+ * start and end of matching text.
+ *
+ * For example, if a contact has an address "123 Main Street", using a filter "mai" would
+ * return the formatted snippet "123 [Mai]n street".
+ *
+ * @see <a href="http://www.sqlite.org/fts3.html#snippet">
+ * http://www.sqlite.org/fts3.html#snippet</a>
*/
public static final String SNIPPET = "snippet";
-
/**
* Comma-separated parameters for the generation of the snippet:
* <ul>
- * <li>The "start match" text. Default is <b></li>
- * <li>The "end match" text. Default is </b></li>
- * <li>The "ellipsis" text. Default is <b>...</b></li>
+ * <li>The "start match" text. Default is '['</li>
+ * <li>The "end match" text. Default is ']'</li>
+ * <li>The "ellipsis" text. Default is "..."</li>
* <li>Maximum number of tokens to include in the snippet. Can be either
* a positive or a negative number: A positive number indicates how many
* tokens can be returned in total. A negative number indicates how many
* tokens can be returned per occurrence of the search terms.</li>
* </ul>
+ *
+ * @hide
*/
public static final String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
/**
- * A key to ask the provider to defer the snippeting to the client if possible.
- * Value of 1 implies true, 0 implies false when 0 is the default.
+ * The key to ask the provider to defer the formatting of the snippet to the client if
+ * possible, for performance reasons.
+ * A value of 1 indicates true, 0 indicates false. False is the default.
* When a cursor is returned to the client, it should check for an extra with the name
* {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
- * should do its own snippeting. If it doesn't exist, the snippet column in the cursor
- * should already contain a snippetized string.
+ * should do its own formatting of the snippet. If it doesn't exist, the snippet column
+ * in the cursor should already contain a formatted snippet.
*/
public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d544804b..33b6d6c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7240,9 +7240,6 @@
if (viewRootImpl != null) {
viewRootImpl.setAccessibilityFocus(this, null);
}
- Rect rect = (mAttachInfo != null) ? mAttachInfo.mTmpInvalRect : new Rect();
- getDrawingRect(rect);
- requestRectangleOnScreen(rect, false);
invalidate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
return true;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 3f72b4c..4ca5863 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -338,7 +338,8 @@
* By default, the animator uses the default interpolator for ValueAnimator. Calling this method
* will cause the declared object to be used instead.
*
- * @param interpolator The TimeInterpolator to be used for ensuing property animations.
+ * @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
+ * of <code>null</code> will result in linear interpolation.
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java
index 8b4277a..31b360c 100644
--- a/core/java/android/view/ViewPropertyAnimatorRT.java
+++ b/core/java/android/view/ViewPropertyAnimatorRT.java
@@ -18,6 +18,8 @@
import android.animation.TimeInterpolator;
import android.view.ViewPropertyAnimator.NameValuesHolder;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
import com.android.internal.view.animation.FallbackLUTInterpolator;
@@ -29,6 +31,8 @@
*/
class ViewPropertyAnimatorRT {
+ private static final Interpolator sLinearInterpolator = new LinearInterpolator();
+
private final View mView;
private RenderNodeAnimator mAnimators[] = new RenderNodeAnimator[RenderNodeAnimator.LAST_VALUE + 1];
@@ -65,6 +69,10 @@
long startDelay = parent.getStartDelay();
long duration = parent.getDuration();
TimeInterpolator interpolator = parent.getInterpolator();
+ if (interpolator == null) {
+ // Documented to be LinearInterpolator in ValueAnimator.setInterpolator
+ interpolator = sLinearInterpolator;
+ }
if (!RenderNodeAnimator.isNativeInterpolator(interpolator)) {
interpolator = new FallbackLUTInterpolator(interpolator, duration);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8567bed..5743882 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -37,8 +37,6 @@
import android.inputmethodservice.ExtractEditText;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -97,6 +95,7 @@
import android.util.TypedValue;
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.ActionMode;
+import android.view.Choreographer;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -9088,26 +9087,22 @@
}
}
- private static final class Marquee extends Handler {
+ private static final class Marquee {
// TODO: Add an option to configure this
private static final float MARQUEE_DELTA_MAX = 0.07f;
private static final int MARQUEE_DELAY = 1200;
private static final int MARQUEE_RESTART_DELAY = 1200;
- private static final int MARQUEE_RESOLUTION = 1000 / 30;
- private static final int MARQUEE_PIXELS_PER_SECOND = 30;
+ private static final int MARQUEE_DP_PER_SECOND = 30;
private static final byte MARQUEE_STOPPED = 0x0;
private static final byte MARQUEE_STARTING = 0x1;
private static final byte MARQUEE_RUNNING = 0x2;
- private static final int MESSAGE_START = 0x1;
- private static final int MESSAGE_TICK = 0x2;
- private static final int MESSAGE_RESTART = 0x3;
-
private final WeakReference<TextView> mView;
+ private final Choreographer mChoreographer;
private byte mStatus = MARQUEE_STOPPED;
- private final float mScrollUnit;
+ private final float mPixelsPerSecond;
private float mMaxScroll;
private float mMaxFadeScroll;
private float mGhostStart;
@@ -9116,49 +9111,62 @@
private int mRepeatLimit;
private float mScroll;
+ private long mLastAnimationMs;
Marquee(TextView v) {
final float density = v.getContext().getResources().getDisplayMetrics().density;
- mScrollUnit = (MARQUEE_PIXELS_PER_SECOND * density) / MARQUEE_RESOLUTION;
+ mPixelsPerSecond = MARQUEE_DP_PER_SECOND * density;
mView = new WeakReference<TextView>(v);
+ mChoreographer = Choreographer.getInstance();
}
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_START:
- mStatus = MARQUEE_RUNNING;
- tick();
- break;
- case MESSAGE_TICK:
- tick();
- break;
- case MESSAGE_RESTART:
- if (mStatus == MARQUEE_RUNNING) {
- if (mRepeatLimit >= 0) {
- mRepeatLimit--;
- }
- start(mRepeatLimit);
- }
- break;
+ private Choreographer.FrameCallback mTickCallback = new Choreographer.FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ tick();
}
- }
+ };
+
+ private Choreographer.FrameCallback mStartCallback = new Choreographer.FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ mStatus = MARQUEE_RUNNING;
+ mLastAnimationMs = mChoreographer.getFrameTime();
+ tick();
+ }
+ };
+
+ private Choreographer.FrameCallback mRestartCallback = new Choreographer.FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ if (mStatus == MARQUEE_RUNNING) {
+ if (mRepeatLimit >= 0) {
+ mRepeatLimit--;
+ }
+ start(mRepeatLimit);
+ }
+ }
+ };
void tick() {
if (mStatus != MARQUEE_RUNNING) {
return;
}
- removeMessages(MESSAGE_TICK);
+ mChoreographer.removeFrameCallback(mTickCallback);
final TextView textView = mView.get();
if (textView != null && (textView.isFocused() || textView.isSelected())) {
- mScroll += mScrollUnit;
+ long currentMs = mChoreographer.getFrameTime();
+ long deltaMs = currentMs - mLastAnimationMs;
+ mLastAnimationMs = currentMs;
+ float deltaPx = deltaMs / 1000f * mPixelsPerSecond;
+ mScroll += deltaPx;
if (mScroll > mMaxScroll) {
mScroll = mMaxScroll;
- sendEmptyMessageDelayed(MESSAGE_RESTART, MARQUEE_RESTART_DELAY);
+ mChoreographer.postFrameCallbackDelayed(mRestartCallback, MARQUEE_DELAY);
} else {
- sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION);
+ mChoreographer.postFrameCallback(mTickCallback);
}
textView.invalidate();
}
@@ -9166,9 +9174,9 @@
void stop() {
mStatus = MARQUEE_STOPPED;
- removeMessages(MESSAGE_START);
- removeMessages(MESSAGE_RESTART);
- removeMessages(MESSAGE_TICK);
+ mChoreographer.removeFrameCallback(mStartCallback);
+ mChoreographer.removeFrameCallback(mRestartCallback);
+ mChoreographer.removeFrameCallback(mTickCallback);
resetScroll();
}
@@ -9199,7 +9207,7 @@
mMaxFadeScroll = mGhostStart + lineWidth + lineWidth;
textView.invalidate();
- sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY);
+ mChoreographer.postFrameCallback(mStartCallback);
}
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 7a9137b..ae9b515 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -58,6 +58,8 @@
void noteVibratorOn(int uid, long durationMillis);
void noteVibratorOff(int uid);
+ void noteFlashlightOn();
+ void noteFlashlightOff();
void noteStartGps(int uid);
void noteStopGps(int uid);
void noteScreenState(int state);
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 6ca24d7..247c8fe 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -54,6 +54,7 @@
PHONE,
WIFI,
BLUETOOTH,
+ FLASHLIGHT,
SCREEN,
APP,
USER,
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 7ff949e..469aa6f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -706,6 +706,15 @@
}
}
+ private void addFlashlightUsage() {
+ long flashlightOnTimeMs = mStats.getFlashlightOnTime(mRawRealtime, mStatsType) / 1000;
+ double flashlightPower = flashlightOnTimeMs
+ * mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT) / (60*60*1000);
+ if (flashlightPower != 0) {
+ addEntry(BatterySipper.DrainType.FLASHLIGHT, flashlightOnTimeMs, flashlightPower);
+ }
+ }
+
private void addUserUsage() {
for (int i=0; i<mUserSippers.size(); i++) {
final int userId = mUserSippers.keyAt(i);
@@ -760,6 +769,7 @@
addUserUsage();
addPhoneUsage();
addScreenUsage();
+ addFlashlightUsage();
addWiFiUsage();
addBluetoothUsage();
addIdleUsage(); // Not including cellular idle power
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 02e4b3f..49d11dc 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -89,7 +89,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 107 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 108 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -260,6 +260,9 @@
boolean mVideoOn;
StopwatchTimer mVideoOnTimer;
+ boolean mFlashlightOn;
+ StopwatchTimer mFlashlightOnTimer;
+
int mPhoneSignalStrengthBin = -1;
int mPhoneSignalStrengthBinRaw = -1;
final StopwatchTimer[] mPhoneSignalStrengthsTimer =
@@ -3177,6 +3180,32 @@
getUidStatsLocked(uid).noteVibratorOffLocked();
}
+ public void noteFlashlightOnLocked() {
+ if (!mFlashlightOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mFlashlightOn = true;
+ mFlashlightOnTimer.startRunningLocked(elapsedRealtime);
+ }
+ }
+
+ public void noteFlashlightOffLocked() {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ if (mFlashlightOn) {
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mFlashlightOn = false;
+ mFlashlightOnTimer.stopRunningLocked(elapsedRealtime);
+ }
+ }
+
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3682,6 +3711,14 @@
return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
}
+ @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
+ return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ }
+
+ @Override public long getFlashlightOnCount(int which) {
+ return mFlashlightOnTimer.getCountLocked(which);
+ }
+
@Override
public long getNetworkActivityBytes(int type, int which) {
if (type >= 0 && type < mNetworkByteActivityCounters.length) {
@@ -5681,6 +5718,7 @@
}
mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+ mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = SystemClock.uptimeMillis() * 1000;
long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -5930,6 +5968,7 @@
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
+ mFlashlightOnTimer.reset(false);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].reset(false);
}
@@ -7124,6 +7163,8 @@
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
}
+ mFlashlightOn = false;
+ mFlashlightOnTimer.readSummaryFromParcelLocked(in);
int NKW = in.readInt();
if (NKW > 10000) {
@@ -7381,6 +7422,7 @@
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
+ mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
@@ -7667,6 +7709,8 @@
mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOn = false;
mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+ mFlashlightOn = false;
+ mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -7798,6 +7842,7 @@
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
}
+ mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
@@ -7931,6 +7976,8 @@
pr.println("*** Bluetooth active type #" + i + ":");
mBluetoothStateTimer[i].logState(pr, " ");
}
+ pr.println("*** Flashlight timer:");
+ mFlashlightOnTimer.logState(pr, " ");
}
super.dumpLocked(context, pw, flags, reqUid, histStart);
}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 94750d3..b3bafa1 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -133,6 +133,11 @@
*/
public static final String POWER_VIDEO = "dsp.video";
+ /**
+ * Power consumption when camera flashlight is on.
+ */
+ public static final String POWER_FLASHLIGHT = "camera.flashlight";
+
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
/**
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index c139c9d..f7886d3 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,6 +1,7 @@
#include "SkBitmap.h"
#include "SkPixelRef.h"
#include "SkImageEncoder.h"
+#include "SkImageInfo.h"
#include "SkColorPriv.h"
#include "GraphicsJNI.h"
#include "SkDither.h"
@@ -97,13 +98,14 @@
}
// can return NULL
-static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
- case SkBitmap::kARGB_4444_Config:
- return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
- case SkBitmap::kRGB_565_Config:
+static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
+ switch (bitmap.colorType()) {
+ case kN32_SkColorType:
+ return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
+ case kARGB_4444_SkColorType:
+ return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
+ FromColor_D4444_Raw;
+ case kRGB_565_SkColorType:
return FromColor_D565;
default:
break;
@@ -112,11 +114,10 @@
}
bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
- int x, int y, int width, int height,
- const SkBitmap& dstBitmap, bool isPremultiplied) {
+ int x, int y, int width, int height, const SkBitmap& dstBitmap) {
SkAutoLockPixels alp(dstBitmap);
void* dst = dstBitmap.getPixels();
- FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
+ FromColorProc proc = ChooseFromColorProc(dstBitmap);
if (NULL == dst || NULL == proc) {
return false;
@@ -257,22 +258,46 @@
}
// can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
+static ToColorProc ChooseToColorProc(const SkBitmap& src) {
switch (src.colorType()) {
case kN32_SkColorType:
- if (src.isOpaque()) return ToColor_S32_Opaque;
- return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
+ switch (src.alphaType()) {
+ case kOpaque_SkAlphaType:
+ return ToColor_S32_Opaque;
+ case kPremul_SkAlphaType:
+ return ToColor_S32_Alpha;
+ case kUnpremul_SkAlphaType:
+ return ToColor_S32_Raw;
+ default:
+ return NULL;
+ }
case kARGB_4444_SkColorType:
- if (src.isOpaque()) return ToColor_S4444_Opaque;
- return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
+ switch (src.alphaType()) {
+ case kOpaque_SkAlphaType:
+ return ToColor_S4444_Opaque;
+ case kPremul_SkAlphaType:
+ return ToColor_S4444_Alpha;
+ case kUnpremul_SkAlphaType:
+ return ToColor_S4444_Raw;
+ default:
+ return NULL;
+ }
case kRGB_565_SkColorType:
return ToColor_S565;
case kIndex_8_SkColorType:
if (src.getColorTable() == NULL) {
return NULL;
}
- if (src.isOpaque()) return ToColor_SI8_Opaque;
- return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
+ switch (src.alphaType()) {
+ case kOpaque_SkAlphaType:
+ return ToColor_SI8_Opaque;
+ case kPremul_SkAlphaType:
+ return ToColor_SI8_Alpha;
+ case kUnpremul_SkAlphaType:
+ return ToColor_SI8_Raw;
+ default:
+ return NULL;
+ }
default:
break;
}
@@ -315,7 +340,7 @@
if (jColors != NULL) {
GraphicsJNI::SetPixels(env, jColors, offset, stride,
- 0, 0, width, height, bitmap, true);
+ 0, 0, width, height, bitmap);
}
return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
@@ -477,20 +502,38 @@
return static_cast<jint>(bitmap->getGenerationID());
}
+static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ if (bitmap->alphaType() == kPremul_SkAlphaType) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+
static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
}
-static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
- jboolean hasAlpha, jboolean isPremul) {
+static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
+ jboolean hasAlpha, jboolean requestPremul) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- if (!hasAlpha) {
- bitmap->setAlphaType(kOpaque_SkAlphaType);
- } else if (isPremul) {
- bitmap->setAlphaType(kPremul_SkAlphaType);
+ if (hasAlpha) {
+ bitmap->setAlphaType(requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
} else {
- bitmap->setAlphaType(kUnpremul_SkAlphaType);
+ bitmap->setAlphaType(kOpaque_SkAlphaType);
+ }
+}
+
+static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
+ jboolean isPremul) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ if (!bitmap->isOpaque()) {
+ if (isPremul) {
+ bitmap->setAlphaType(kPremul_SkAlphaType);
+ } else {
+ bitmap->setAlphaType(kUnpremul_SkAlphaType);
+ }
}
}
@@ -661,11 +704,11 @@
///////////////////////////////////////////////////////////////////////////////
static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
- jint x, jint y, jboolean isPremultiplied) {
+ jint x, jint y) {
const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkAutoLockPixels alp(*bitmap);
- ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+ ToColorProc proc = ChooseToColorProc(*bitmap);
if (NULL == proc) {
return 0;
}
@@ -681,11 +724,11 @@
static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
jintArray pixelArray, jint offset, jint stride,
- jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+ jint x, jint y, jint width, jint height) {
const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkAutoLockPixels alp(*bitmap);
- ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+ ToColorProc proc = ChooseToColorProc(*bitmap);
if (NULL == proc) {
return;
}
@@ -708,7 +751,7 @@
///////////////////////////////////////////////////////////////////////////////
static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
- jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
+ jint x, jint y, jint colorHandle) {
const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkColor color = static_cast<SkColor>(colorHandle);
SkAutoLockPixels alp(*bitmap);
@@ -716,7 +759,7 @@
return;
}
- FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
+ FromColorProc proc = ChooseFromColorProc(*bitmap);
if (NULL == proc) {
return;
}
@@ -727,10 +770,10 @@
static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
jintArray pixelArray, jint offset, jint stride,
- jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+ jint x, jint y, jint width, jint height) {
const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
- x, y, width, height, *bitmap, isPremultiplied);
+ x, y, width, height, *bitmap);
}
static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
@@ -834,7 +877,9 @@
{ "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
{ "nativeConfig", "(J)I", (void*)Bitmap_config },
{ "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
- { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
+ { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
+ { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
+ { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
{ "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
{ "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
{ "nativeCreateFromParcel",
@@ -845,10 +890,10 @@
{ "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
(void*)Bitmap_extractAlpha },
{ "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
- { "nativeGetPixel", "(JIIZ)I", (void*)Bitmap_getPixel },
- { "nativeGetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
- { "nativeSetPixel", "(JIIIZ)V", (void*)Bitmap_setPixel },
- { "nativeSetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
+ { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
+ { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
+ { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
+ { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
{ "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
(void*)Bitmap_copyPixelsToBuffer },
{ "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3f323ab..6254f3d 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -24,6 +24,7 @@
#include "SkDeque.h"
#include "SkDrawFilter.h"
#include "SkGraphics.h"
+#include <SkImageInfo.h>
#include "SkPorterDuff.h"
#include "SkShader.h"
#include "SkTArray.h"
@@ -699,6 +700,8 @@
jboolean hasAlpha, jlong paintHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
+ // correct the alphaType to kOpaque_SkAlphaType.
SkImageInfo info = SkImageInfo::Make(width, height,
hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
kPremul_SkAlphaType);
@@ -708,7 +711,7 @@
}
if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
- 0, 0, width, height, bitmap, true)) {
+ 0, 0, width, height, bitmap)) {
return;
}
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 7fda3d9..0ad7fd8 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -90,10 +90,11 @@
/** Copy the colors in colors[] to the bitmap, convert to the correct
format along the way.
+ Whether to use premultiplied pixels is determined by dstBitmap's alphaType.
*/
static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
int srcStride, int x, int y, int width, int height,
- const SkBitmap& dstBitmap, bool isPremultiplied);
+ const SkBitmap& dstBitmap);
static jbyteArray getBitmapStorageObj(SkPixelRef *pixref);
};
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b38f5f2..c352398 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -30,6 +30,7 @@
#include <SkBitmap.h>
#include <SkCanvas.h>
+#include <SkImageInfo.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPorterDuff.h>
@@ -376,6 +377,8 @@
static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
jlong rendererPtr, jintArray colors, jint offset, jint stride,
jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, jlong paintPtr) {
+ // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
+ // correct the alphaType to kOpaque_SkAlphaType.
const SkImageInfo info = SkImageInfo::Make(width, height,
hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
kPremul_SkAlphaType);
@@ -385,7 +388,7 @@
return;
}
- if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap, true)) {
+ if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap)) {
delete bitmap;
return;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7db478d..450a889 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -99,6 +99,7 @@
<protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.UUID" />
+ <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
<protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
<protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
@@ -396,6 +397,15 @@
android:label="@string/permlab_receiveWapPush"
android:description="@string/permdesc_receiveWapPush" />
+ <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
+ or perform processing on them. -->
+ <!-- @hide -->
+ <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
+ android:permissionGroup="android.permission-group.MESSAGES"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_receiveBluetoothMap"
+ android:description="@string/permdesc_receiveBluetoothMap" />
+
<!-- =============================================================== -->
<!-- Permissions for accessing social info (contacts and social) -->
<!-- =============================================================== -->
diff --git a/core/res/res/anim/progress_indeterminate_rotation_material.xml b/core/res/res/anim/progress_indeterminate_rotation_material.xml
new file mode 100644
index 0000000..5d3ba22
--- /dev/null
+++ b/core/res/res/anim/progress_indeterminate_rotation_material.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:duration="6665"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="rotation"
+ android:repeatCount="-1"
+ android:valueFrom="0"
+ android:valueTo="720"
+ android:valueType="floatType" />
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
index 341d2a9..526f914 100644
--- a/core/res/res/drawable/progress_large_material.xml
+++ b/core/res/res/drawable/progress_large_material.xml
@@ -21,4 +21,8 @@
android:name="progressBar"
android:animation="@anim/progress_indeterminate_material" />
+ <target
+ android:name="root"
+ android:animation="@anim/progress_indeterminate_rotation_material" />
+
</animated-vector>
diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
index 1f2622c..cc35816 100644
--- a/core/res/res/drawable/progress_medium_material.xml
+++ b/core/res/res/drawable/progress_medium_material.xml
@@ -20,4 +20,8 @@
android:name="progressBar"
android:animation="@anim/progress_indeterminate_material" />
+ <target
+ android:name="root"
+ android:animation="@anim/progress_indeterminate_rotation_material" />
+
</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
index 43bc569..c6e4380 100644
--- a/core/res/res/drawable/progress_small_material.xml
+++ b/core/res/res/drawable/progress_small_material.xml
@@ -21,4 +21,8 @@
android:name="progressBar"
android:animation="@anim/progress_indeterminate_material" />
+ <target
+ android:name="root"
+ android:animation="@anim/progress_indeterminate_rotation_material" />
+
</animated-vector>
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
index b1900cb..6e0840c 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
@@ -25,8 +25,6 @@
<group
android:name="root"
- android:scaleX="1.0"
- android:scaleY="1.0"
android:translateX="24.0"
android:translateY="24.0" >
<path
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
index 57a6163..7f1231c 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
@@ -25,8 +25,6 @@
<group
android:name="root"
- android:scaleX="1.0"
- android:scaleY="1.0"
android:translateX="24.0"
android:translateY="24.0" >
<path
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
index ea949b7..58ca101 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
@@ -25,8 +25,6 @@
<group
android:name="root"
- android:scaleX="1.0"
- android:scaleY="1.0"
android:translateX="24.0"
android:translateY="24.0" >
<path
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a3262ed..a71ed47 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -761,6 +761,13 @@
messages sent to you without showing them to you.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_receiveBluetoothMap">receive Bluetooth messages (MAP)</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_receiveBluetoothMap">Allows the app to receive and process Bluetooth MAP
+ messages. This means the app could monitor or delete messages sent to your
+ device without showing them to you.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_getTasks">retrieve running apps</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_getTasks">Allows the app to retrieve information
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 3857ec0..91f5896 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -141,4 +141,8 @@
<library name="javax.obex"
file="/system/framework/javax.obex.jar"/>
+ <!-- These are the standard packages that are white-listed to always have internet
+ access while in power save mode, even if they aren't in the foreground. -->
+ <allow-in-power-save package="com.android.providers.downloads" />
+
</permissions>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ef0a411..9d7ef45 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -59,14 +59,18 @@
private final boolean mIsMutable;
/**
- * Represents whether the Bitmap's content is expected to be pre-multiplied.
+ * Represents whether the Bitmap's content is requested to be pre-multiplied.
* Note that isPremultiplied() does not directly return this value, because
- * isPremultiplied() may never return true for a 565 Bitmap.
+ * isPremultiplied() may never return true for a 565 Bitmap or a bitmap
+ * without alpha.
*
* setPremultiplied() does directly set the value so that setConfig() and
* setPremultiplied() aren't order dependent, despite being setters.
+ *
+ * The native bitmap's premultiplication state is kept up to date by
+ * pushing down this preference for every config change.
*/
- private boolean mIsPremultiplied;
+ private boolean mRequestPremultiplied;
private byte[] mNinePatchChunk; // may be null
private int[] mLayoutBounds; // may be null
@@ -105,7 +109,7 @@
*/
@SuppressWarnings({"UnusedDeclaration"}) // called from JNI
Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
- boolean isMutable, boolean isPremultiplied,
+ boolean isMutable, boolean requestPremultiplied,
byte[] ninePatchChunk, int[] layoutBounds) {
if (nativeBitmap == 0) {
throw new RuntimeException("internal error: native bitmap is 0");
@@ -114,7 +118,7 @@
mWidth = width;
mHeight = height;
mIsMutable = isMutable;
- mIsPremultiplied = isPremultiplied;
+ mRequestPremultiplied = requestPremultiplied;
mBuffer = buffer;
// we delete this in our finalizer
mNativeBitmap = nativeBitmap;
@@ -132,10 +136,10 @@
* width/height values
*/
@SuppressWarnings({"UnusedDeclaration"}) // called from JNI
- void reinit(int width, int height, boolean isPremultiplied) {
+ void reinit(int width, int height, boolean requestPremultiplied) {
mWidth = width;
mHeight = height;
- mIsPremultiplied = isPremultiplied;
+ mRequestPremultiplied = requestPremultiplied;
}
/**
@@ -223,7 +227,7 @@
}
nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
- mIsPremultiplied);
+ mRequestPremultiplied);
mWidth = width;
mHeight = height;
}
@@ -561,7 +565,7 @@
checkRecycled("Can't copy a recycled bitmap");
Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
if (b != null) {
- b.setAlphaAndPremultiplied(hasAlpha(), mIsPremultiplied);
+ b.setPremultiplied(mRequestPremultiplied);
b.mDensity = mDensity;
}
return b;
@@ -738,7 +742,8 @@
// The new bitmap was created from a known bitmap source so assume that
// they use the same density
bitmap.mDensity = source.mDensity;
- bitmap.setAlphaAndPremultiplied(source.hasAlpha(), source.mIsPremultiplied);
+ bitmap.setHasAlpha(source.hasAlpha());
+ bitmap.setPremultiplied(source.mRequestPremultiplied);
canvas.setBitmap(bitmap);
canvas.drawBitmap(source, srcR, dstR, paint);
@@ -1018,6 +1023,9 @@
* <p>This method always returns false if {@link #getConfig()} is
* {@link Bitmap.Config#RGB_565}.</p>
*
+ * <p>The return value is undefined if {@link #getConfig()} is
+ * {@link Bitmap.Config#ALPHA_8}.</p>
+ *
* <p>This method only returns true if {@link #hasAlpha()} returns true.
* A bitmap with no alpha channel can be used both as a pre-multiplied and
* as a non pre-multiplied bitmap.</p>
@@ -1033,7 +1041,7 @@
* @see BitmapFactory.Options#inPremultiplied
*/
public final boolean isPremultiplied() {
- return mIsPremultiplied && getConfig() != Config.RGB_565 && hasAlpha();
+ return nativeIsPremultiplied(mNativeBitmap);
}
/**
@@ -1057,14 +1065,8 @@
* @see BitmapFactory.Options#inPremultiplied
*/
public final void setPremultiplied(boolean premultiplied) {
- mIsPremultiplied = premultiplied;
- nativeSetAlphaAndPremultiplied(mNativeBitmap, hasAlpha(), premultiplied);
- }
-
- /** Helper function to set both alpha and premultiplied. **/
- private final void setAlphaAndPremultiplied(boolean hasAlpha, boolean premultiplied) {
- mIsPremultiplied = premultiplied;
- nativeSetAlphaAndPremultiplied(mNativeBitmap, hasAlpha, premultiplied);
+ mRequestPremultiplied = premultiplied;
+ nativeSetPremultiplied(mNativeBitmap, premultiplied);
}
/** Returns the bitmap's width */
@@ -1225,7 +1227,7 @@
* non-opaque per-pixel alpha values.
*/
public void setHasAlpha(boolean hasAlpha) {
- nativeSetAlphaAndPremultiplied(mNativeBitmap, hasAlpha, mIsPremultiplied);
+ nativeSetHasAlpha(mNativeBitmap, hasAlpha, mRequestPremultiplied);
}
/**
@@ -1299,7 +1301,7 @@
public int getPixel(int x, int y) {
checkRecycled("Can't call getPixel() on a recycled bitmap");
checkPixelAccess(x, y);
- return nativeGetPixel(mNativeBitmap, x, y, mIsPremultiplied);
+ return nativeGetPixel(mNativeBitmap, x, y);
}
/**
@@ -1333,7 +1335,7 @@
}
checkPixelsAccess(x, y, width, height, offset, stride, pixels);
nativeGetPixels(mNativeBitmap, pixels, offset, stride,
- x, y, width, height, mIsPremultiplied);
+ x, y, width, height);
}
/**
@@ -1413,7 +1415,7 @@
throw new IllegalStateException();
}
checkPixelAccess(x, y);
- nativeSetPixel(mNativeBitmap, x, y, color, mIsPremultiplied);
+ nativeSetPixel(mNativeBitmap, x, y, color);
}
/**
@@ -1450,7 +1452,7 @@
}
checkPixelsAccess(x, y, width, height, offset, stride, pixels);
nativeSetPixels(mNativeBitmap, pixels, offset, stride,
- x, y, width, height, mIsPremultiplied);
+ x, y, width, height);
}
public static final Parcelable.Creator<Bitmap> CREATOR
@@ -1602,17 +1604,15 @@
private static native int nativeRowBytes(long nativeBitmap);
private static native int nativeConfig(long nativeBitmap);
- private static native int nativeGetPixel(long nativeBitmap, int x, int y,
- boolean isPremultiplied);
+ private static native int nativeGetPixel(long nativeBitmap, int x, int y);
private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
int offset, int stride, int x, int y,
- int width, int height, boolean isPremultiplied);
+ int width, int height);
- private static native void nativeSetPixel(long nativeBitmap, int x, int y,
- int color, boolean isPremultiplied);
+ private static native void nativeSetPixel(long nativeBitmap, int x, int y, int color);
private static native void nativeSetPixels(long nativeBitmap, int[] colors,
int offset, int stride, int x, int y,
- int width, int height, boolean isPremultiplied);
+ int width, int height);
private static native void nativeCopyPixelsToBuffer(long nativeBitmap,
Buffer dst);
private static native void nativeCopyPixelsFromBuffer(long nativeBitmap, Buffer src);
@@ -1631,9 +1631,12 @@
private static native void nativePrepareToDraw(long nativeBitmap);
private static native boolean nativeHasAlpha(long nativeBitmap);
- private static native void nativeSetAlphaAndPremultiplied(long nativeBitmap,
- boolean hasAlpha,
- boolean isPremul);
+ private static native boolean nativeIsPremultiplied(long nativeBitmap);
+ private static native void nativeSetPremultiplied(long nativeBitmap,
+ boolean isPremul);
+ private static native void nativeSetHasAlpha(long nativeBitmap,
+ boolean hasAlpha,
+ boolean requestPremul);
private static native boolean nativeHasMipMap(long nativeBitmap);
private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 57c66da..d553d10 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -427,24 +427,46 @@
return 0;
}
+ /**
+ * @hide
+ * Used to indicate that when parcelling, the tags should be parcelled through the flattened
+ * formatted string, not through the array of strings.
+ * Keep in sync with frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
+ * see definition of kAudioAttributesMarshallTagFlattenTags
+ */
+ public final static int FLATTEN_TAGS = 0x1;
+ /**
+ * When adding tags for writeToParcel(Parcel, int), add them in the list of flags (| NEW_FLAG)
+ */
+ private final static int ALL_PARCEL_FLAGS = FLATTEN_TAGS;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mUsage);
dest.writeInt(mContentType);
dest.writeInt(mFlags);
- String[] tagsArray = new String[mTags.size()];
- mTags.toArray(tagsArray);
- dest.writeStringArray(tagsArray);
+ dest.writeInt(flags & ALL_PARCEL_FLAGS);
+ if ((flags & FLATTEN_TAGS) == 0) {
+ String[] tagsArray = new String[mTags.size()];
+ mTags.toArray(tagsArray);
+ dest.writeStringArray(tagsArray);
+ } else if ((flags & FLATTEN_TAGS) == FLATTEN_TAGS) {
+ dest.writeString(mFormattedTags);
+ }
}
private AudioAttributes(Parcel in) {
mUsage = in.readInt();
mContentType = in.readInt();
mFlags = in.readInt();
+ boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS);
mTags = new HashSet<String>();
- String[] tagsArray = in.readStringArray();
- for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
- mTags.add(tagsArray[i]);
+ if (hasFlattenedTags) {
+ mTags.add(in.readString());
+ } else {
+ String[] tagsArray = in.readStringArray();
+ for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
+ mTags.add(tagsArray[i]);
+ }
}
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index d882bc8..628d35b 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -63,6 +63,8 @@
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.System;
+
+import android.telecomm.TelecommManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -2725,17 +2727,13 @@
}
private boolean isInCommunication() {
- boolean isOffhook = false;
+ boolean isInAPhoneCall = false;
- if (mVoiceCapable) {
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) isOffhook = phone.isOffhook();
- } catch (RemoteException e) {
- Log.w(TAG, "Couldn't connect to phone service", e);
- }
- }
- return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
+ TelecommManager telecommManager =
+ (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
+ isInAPhoneCall = telecommManager.isInAPhoneCall();
+
+ return (isInAPhoneCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
}
/**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index d1909bc..490a8fd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1441,6 +1441,36 @@
private native void _setAudioStreamType(int streamtype);
+ // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer.h
+ private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
+ /**
+ * Sets the parameter indicated by key.
+ * @param key key indicates the parameter to be set.
+ * @param value value of the parameter to be set.
+ * @return true if the parameter is set successfully, false otherwise
+ * {@hide}
+ */
+ private native boolean setParameter(int key, Parcel value);
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Must call this method before prepare() or
+ * prepareAsync() in order for the audio attributes to become effective
+ * thereafter.
+ * @param attributes a non-null set of audio attributes
+ */
+ public void setAudioAttributes(AudioAttributes attributes) throws IllegalArgumentException {
+ if (attributes == null) {
+ final String msg = "Cannot set audio attributes to null";
+ throw new IllegalArgumentException(msg);
+ }
+ Parcel pattributes = Parcel.obtain();
+ attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
+ setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
+ pattributes.recycle();
+ }
+
/**
* Sets the player to be looping or non-looping.
*
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9516bf8..1255276 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1185,6 +1185,7 @@
HashSet<String> existingFiles = new HashSet<String>();
String directory = "/sdcard/DCIM/.thumbnails";
String [] files = (new File(directory)).list();
+ Cursor c = null;
if (files == null)
files = new String[0];
@@ -1194,7 +1195,7 @@
}
try {
- Cursor c = mMediaProvider.query(
+ c = mMediaProvider.query(
mPackageName,
mThumbsUri,
new String [] { "_data" },
@@ -1219,11 +1220,12 @@
}
Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
+ } catch (RemoteException e) {
+ // We will soon be killed...
+ } finally {
if (c != null) {
c.close();
}
- } catch (RemoteException e) {
- // We will soon be killed...
}
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6f42057..4587cf56 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -514,6 +514,25 @@
return (jint) streamtype;
}
+static jboolean
+android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
+{
+ ALOGV("setParameter: key %d", key);
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ Parcel *request = parcelForJavaObject(env, java_request);
+ status_t err = mp->setParameter(key, *request);
+ if (err == OK) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
static void
android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
{
@@ -857,6 +876,7 @@
{"_reset", "()V", (void *)android_media_MediaPlayer_reset},
{"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
{"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType},
+ {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
{"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 0c65283..75278b5 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2014 The Android Open Source Project
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
@@ -66,6 +67,8 @@
private boolean mGetOperation;
+ private boolean mGetFinalFlag;
+
private HeaderSet mRequestHeader;
private HeaderSet mReplyHeader;
@@ -90,6 +93,7 @@
mOperationDone = false;
mMaxPacketSize = maxSize;
mGetOperation = type;
+ mGetFinalFlag = false;
mPrivateInputOpen = false;
mPrivateOutputOpen = false;
@@ -131,6 +135,15 @@
}
/**
+ * Allows to set flag which will force GET to be always sent as single packet request with
+ * final flag set. This is to improve compatibility with some profiles, i.e. PBAP which
+ * require requests to be sent this way.
+ */
+ public void setGetFinalFlag(boolean flag) {
+ mGetFinalFlag = flag;
+ }
+
+ /**
* Sends an ABORT message to the server. By calling this method, the
* corresponding input and output streams will be closed along with this
* object.
@@ -551,15 +564,25 @@
if (mGetOperation) {
if (!mOperationDone) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- more = sendRequest(0x03);
- }
+ if (!mGetFinalFlag) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x03);
+ }
- if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
- mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
- }
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ }
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ } else {
+ more = sendRequest(0x83);
+
+ if (more) {
+ throw new IOException("FINAL_GET forced but data did not fit into single packet!");
+ }
+
mOperationDone = true;
}
}
@@ -613,7 +636,16 @@
if (mPrivateInput == null) {
mPrivateInput = new PrivateInputStream(this);
}
- sendRequest(0x03);
+
+ if (!mGetFinalFlag) {
+ sendRequest(0x03);
+ } else {
+ sendRequest(0x83);
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
return true;
} else if (mOperationDone) {
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
index 2b3066f..51b560a 100644
--- a/obex/javax/obex/HeaderSet.java
+++ b/obex/javax/obex/HeaderSet.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2014 The Android Open Source Project
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
@@ -181,6 +182,8 @@
private String mName; // null terminated Unicode text string
+ private boolean mEmptyName;
+
private String mType; // null terminated ASCII text string
private Long mLength; // 4 byte unsigend integer
@@ -235,6 +238,25 @@
}
/**
+ * Sets flag for special "value" of NAME header which should be empty. This
+ * is not the same as NAME header with empty string in which case it will
+ * have length of 5 bytes. It should be 3 bytes with only header id and
+ * length field.
+ */
+ public void setEmptyNameHeader() {
+ mName = null;
+ mEmptyName = true;
+ }
+
+ /**
+ * Gets flag for special "value" of NAME header which should be empty. See
+ * above.
+ */
+ public boolean getEmptyNameHeader() {
+ return mEmptyName;
+ }
+
+ /**
* Sets the value of the header identifier to the value provided. The type
* of object must correspond to the Java type defined in the description of
* this interface. If <code>null</code> is passed as the
@@ -269,6 +291,7 @@
if ((headerValue != null) && (!(headerValue instanceof String))) {
throw new IllegalArgumentException("Name must be a String");
}
+ mEmptyName = false;
mName = (String)headerValue;
break;
case TYPE:
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 8c12a20..0a06709 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2014 The Android Open Source Project
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
@@ -387,6 +388,11 @@
if (nullOut) {
headImpl.setHeader(HeaderSet.NAME, null);
}
+ } else if (headImpl.getEmptyNameHeader()) {
+ out.write((byte) HeaderSet.NAME);
+ lengthArray[0] = (byte) 0x00;
+ lengthArray[1] = (byte) 0x03;
+ out.write(lengthArray);
}
// Type Header
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0720704..d152887 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -50,6 +50,7 @@
private int mPanelPaddingBottom;
private int mDualTileUnderlap;
private boolean mExpanded;
+ private boolean mListening;
private TileRecord mDetailRecord;
private Callback mCallback;
@@ -100,9 +101,14 @@
if (!mExpanded) {
showDetail(false /*show*/, mDetailRecord);
}
+ }
+
+ public void setListening(boolean listening) {
+ if (mListening == listening) return;
+ mListening = listening;
for (TileRecord r : mRecords) {
- r.tile.setListening(mExpanded);
- if (mExpanded) {
+ r.tile.setListening(mListening);
+ if (mListening) {
r.tile.refreshState();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c82bdf6..fd2db8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -35,6 +35,7 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
@@ -61,7 +62,7 @@
private KeyguardPageSwipeHelper mPageSwiper;
private StatusBarHeaderView mHeader;
private View mQsContainer;
- private View mQsPanel;
+ private QSPanel mQsPanel;
private View mKeyguardStatusView;
private ObservableScrollView mScrollView;
private TextView mClockView;
@@ -136,7 +137,7 @@
mHeader.setOverlayParent(this);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
mQsContainer = findViewById(R.id.quick_settings_container);
- mQsPanel = findViewById(R.id.quick_settings_panel);
+ mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
mClockView = (TextView) findViewById(R.id.clock_view);
mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
mScrollView.setListener(this);
@@ -873,6 +874,20 @@
super.onExpandingFinished();
mNotificationStackScroller.onExpansionStopped();
mIsExpanding = false;
+ if (mExpandedHeight == 0f) {
+ mHeader.setListening(false);
+ mQsPanel.setListening(false);
+ } else {
+ mHeader.setListening(true);
+ mQsPanel.setListening(true);
+ }
+ }
+
+ @Override
+ public void instantExpand() {
+ super.instantExpand();
+ mHeader.setListening(true);
+ mQsPanel.setListening(true);
}
@Override
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 f70010e..03c23e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -31,7 +31,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
@@ -518,7 +517,7 @@
Resources res = context.getResources();
updateDisplaySize(); // populates mDisplayMetrics
- loadDimens();
+ updateResources();
mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 9e9de5d..3e2dcef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -45,6 +45,7 @@
private static final float EXPANSION_RUBBERBAND_FACTOR = 0.35f;
private boolean mExpanded;
+ private boolean mListening;
private boolean mOverscrolled;
private boolean mKeyguardShowing;
@@ -145,6 +146,14 @@
return mExpandedHeight;
}
+ public void setListening(boolean listening) {
+ if (listening == mListening) {
+ return;
+ }
+ mListening = listening;
+ updateBrightnessControllerState();
+ }
+
public void setExpanded(boolean expanded, boolean overscrolled) {
boolean changed = expanded != mExpanded;
boolean overscrollChanged = overscrolled != mOverscrolled;
@@ -154,7 +163,6 @@
updateHeights();
updateVisibilities();
updateSystemIconsLayoutParams();
- updateBrightnessControllerState();
updateZTranslation();
updateClickTargets();
updateWidth();
@@ -254,7 +262,7 @@
}
private void updateBrightnessControllerState() {
- if (mExpanded) {
+ if (mListening) {
mBrightnessController.registerCallbacks();
} else {
mBrightnessController.unregisterCallbacks();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ddfa9c1..95edf07 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -64,7 +64,7 @@
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
-import android.telephony.TelephonyManager;
+import android.telecomm.TelecommManager;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -2038,8 +2038,8 @@
ServiceManager.checkService(DreamService.DREAM_SERVICE));
}
- TelephonyManager getTelephonyService() {
- return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ TelecommManager getTelecommService() {
+ return (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
}
static IAudioService getAudioService() {
@@ -2126,10 +2126,10 @@
}
// If an incoming call is ringing, HOME is totally disabled.
- // (The user is already on the InCallScreen at this point,
+ // (The user is already on the InCallUI at this point,
// and his ONLY options are to answer or reject the call.)
- TelephonyManager telephonyManager = getTelephonyService();
- if (telephonyManager != null && telephonyManager.isRinging()) {
+ TelecommManager telecommManager = getTelecommService();
+ if (telecommManager != null && telecommManager.isRinging()) {
Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
return -1;
}
@@ -4152,9 +4152,9 @@
}
}
if (down) {
- TelephonyManager telephonyManager = getTelephonyService();
- if (telephonyManager != null) {
- if (telephonyManager.isRinging()) {
+ TelecommManager telecommManager = getTelecommService();
+ if (telecommManager != null) {
+ if (telecommManager.isRinging()) {
// If an incoming call is ringing, either VOLUME key means
// "silence ringer". We handle these keys here, rather than
// in the InCallScreen, to make sure we'll respond to them
@@ -4166,14 +4166,14 @@
// Silence the ringer. (It's safe to call this
// even if the ringer has already been silenced.)
- telephonyManager.silenceRinger();
+ telecommManager.silenceRinger();
// And *don't* pass this key thru to the current activity
// (which is probably the InCallScreen.)
result &= ~ACTION_PASS_TO_USER;
break;
}
- if (telephonyManager.isOffhook()
+ if (telecommManager.isInAPhoneCall()
&& (result & ACTION_PASS_TO_USER) == 0) {
// If we are in call but we decided not to pass the key to
// the application, just pass it to the session service.
@@ -4199,10 +4199,10 @@
case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- TelephonyManager telephonyManager = getTelephonyService();
+ TelecommManager telecommManager = getTelecommService();
boolean hungUp = false;
- if (telephonyManager != null) {
- hungUp = telephonyManager.endCall();
+ if (telecommManager != null) {
+ hungUp = telecommManager.endCall();
}
interceptPowerKeyDown(!interactive || hungUp);
} else {
@@ -4238,19 +4238,19 @@
interceptScreenshotChord();
}
- TelephonyManager telephonyManager = getTelephonyService();
+ TelecommManager telecommManager = getTelecommService();
boolean hungUp = false;
- if (telephonyManager != null) {
- if (telephonyManager.isRinging()) {
+ if (telecommManager != null) {
+ if (telecommManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
- telephonyManager.silenceRinger();
+ telecommManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
- && telephonyManager.isOffhook() && interactive) {
+ && telecommManager.isInAPhoneCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
- hungUp = telephonyManager.endCall();
+ hungUp = telecommManager.endCall();
}
}
interceptPowerKeyDown(!interactive || hungUp
@@ -4286,9 +4286,9 @@
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (down) {
- TelephonyManager telephonyManager = getTelephonyService();
- if (telephonyManager != null) {
- if (!telephonyManager.isIdle()) {
+ TelecommManager telecommManager = getTelecommService();
+ if (telecommManager != null) {
+ if (telecommManager.isInAPhoneCall()) {
// Suppress PLAY/PAUSE toggle when phone is ringing or in-call
// to avoid music playback.
break;
@@ -4321,12 +4321,12 @@
case KeyEvent.KEYCODE_CALL: {
if (down) {
- TelephonyManager telephonyManager = getTelephonyService();
- if (telephonyManager != null) {
- if (telephonyManager.isRinging()) {
+ TelecommManager telecommManager = getTelecommService();
+ if (telecommManager != null) {
+ if (telecommManager.isRinging()) {
Log.i(TAG, "interceptKeyBeforeQueueing:"
+ " CALL key-down while ringing: Answer the call!");
- telephonyManager.answerRingingCall();
+ telecommManager.acceptRingingCall();
// And *don't* pass this key thru to the current activity
// (which is presumably the InCallScreen.)
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
new file mode 100644
index 0000000..fdcb3b9
--- /dev/null
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.pm.FeatureInfo;
+import android.os.*;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import static com.android.internal.util.ArrayUtils.appendInt;
+
+/**
+ * Loads global system configuration info.
+ */
+public class SystemConfig {
+ static final String TAG = "SystemConfig";
+
+ static SystemConfig sInstance;
+
+ // Group-ids that are given to all packages as read from etc/permissions/*.xml.
+ int[] mGlobalGids;
+
+ // These are the built-in uid -> permission mappings that were read from the
+ // system configuration files.
+ final SparseArray<HashSet<String>> mSystemPermissions =
+ new SparseArray<HashSet<String>>();
+
+ // These are the built-in shared libraries that were read from the
+ // system configuration files. Keys are the library names; strings are the
+ // paths to the libraries.
+ final ArrayMap<String, String> mSharedLibraries
+ = new ArrayMap<String, String>();
+
+ // These are the features this devices supports that were read from the
+ // system configuration files.
+ final HashMap<String, FeatureInfo> mAvailableFeatures =
+ new HashMap<String, FeatureInfo>();
+
+ public static final class PermissionEntry {
+ public final String name;
+ public int[] gids;
+
+ PermissionEntry(String _name) {
+ name = _name;
+ }
+ }
+
+ // These are the permission -> gid mappings that were read from the
+ // system configuration files.
+ final ArrayMap<String, PermissionEntry> mPermissions =
+ new ArrayMap<String, PermissionEntry>();
+
+ // These are the packages that are white-listed to be able to run in the
+ // background while in power save mode, as read from the configuration files.
+ final ArraySet<String> mAllowInPowerSave = new ArraySet<String>();
+
+ public static SystemConfig getInstance() {
+ synchronized (SystemConfig.class) {
+ if (sInstance == null) {
+ sInstance = new SystemConfig();
+ }
+ return sInstance;
+ }
+ }
+
+ public int[] getGlobalGids() {
+ return mGlobalGids;
+ }
+
+ public SparseArray<HashSet<String>> getSystemPermissions() {
+ return mSystemPermissions;
+ }
+
+ public ArrayMap<String, String> getSharedLibraries() {
+ return mSharedLibraries;
+ }
+
+ public HashMap<String, FeatureInfo> getAvailableFeatures() {
+ return mAvailableFeatures;
+ }
+
+ public ArrayMap<String, PermissionEntry> getPermissions() {
+ return mPermissions;
+ }
+
+ public ArraySet<String> getAllowInPowerSave() {
+ return mAllowInPowerSave;
+ }
+
+ SystemConfig() {
+ // Read configuration from system
+ readPermissions(Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "sysconfig"), false);
+ // Read configuration from the old permissions dir
+ readPermissions(Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "permissions"), false);
+ // Only read features from OEM config
+ readPermissions(Environment.buildPath(
+ Environment.getOemDirectory(), "etc", "sysconfig"), true);
+ readPermissions(Environment.buildPath(
+ Environment.getOemDirectory(), "etc", "permissions"), true);
+ }
+
+ void readPermissions(File libraryDir, boolean onlyFeatures) {
+ // Read permissions from given directory.
+ if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+ if (!onlyFeatures) {
+ Slog.w(TAG, "No directory " + libraryDir + ", skipping");
+ }
+ return;
+ }
+ if (!libraryDir.canRead()) {
+ Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
+ return;
+ }
+
+ // Iterate over the files in the directory and scan .xml files
+ for (File f : libraryDir.listFiles()) {
+ // We'll read platform.xml last
+ if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+ continue;
+ }
+
+ if (!f.getPath().endsWith(".xml")) {
+ Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
+ continue;
+ }
+ if (!f.canRead()) {
+ Slog.w(TAG, "Permissions library file " + f + " cannot be read");
+ continue;
+ }
+
+ readPermissionsFromXml(f, onlyFeatures);
+ }
+
+ // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
+ final File permFile = new File(Environment.getRootDirectory(),
+ "etc/permissions/platform.xml");
+ readPermissionsFromXml(permFile, onlyFeatures);
+ }
+
+ private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
+ FileReader permReader = null;
+ try {
+ permReader = new FileReader(permFile);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
+ return;
+ }
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(permReader);
+
+ int type;
+ while ((type=parser.next()) != parser.START_TAG
+ && type != parser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != parser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
+ throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
+ ", expected 'permissions' or 'config'");
+ }
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+ if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+ break;
+ }
+
+ String name = parser.getName();
+ if ("group".equals(name) && !onlyFeatures) {
+ String gidStr = parser.getAttributeValue(null, "gid");
+ if (gidStr != null) {
+ int gid = android.os.Process.getGidForName(gidStr);
+ mGlobalGids = appendInt(mGlobalGids, gid);
+ } else {
+ Slog.w(TAG, "<group> without gid at "
+ + parser.getPositionDescription());
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ } else if ("permission".equals(name) && !onlyFeatures) {
+ String perm = parser.getAttributeValue(null, "name");
+ if (perm == null) {
+ Slog.w(TAG, "<permission> without name at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ perm = perm.intern();
+ readPermission(parser, perm);
+
+ } else if ("assign-permission".equals(name) && !onlyFeatures) {
+ String perm = parser.getAttributeValue(null, "name");
+ if (perm == null) {
+ Slog.w(TAG, "<assign-permission> without name at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ String uidStr = parser.getAttributeValue(null, "uid");
+ if (uidStr == null) {
+ Slog.w(TAG, "<assign-permission> without uid at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ int uid = Process.getUidForName(uidStr);
+ if (uid < 0) {
+ Slog.w(TAG, "<assign-permission> with unknown uid \""
+ + uidStr + "\" at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ perm = perm.intern();
+ HashSet<String> perms = mSystemPermissions.get(uid);
+ if (perms == null) {
+ perms = new HashSet<String>();
+ mSystemPermissions.put(uid, perms);
+ }
+ perms.add(perm);
+ XmlUtils.skipCurrentTag(parser);
+
+ } else if ("library".equals(name) && !onlyFeatures) {
+ String lname = parser.getAttributeValue(null, "name");
+ String lfile = parser.getAttributeValue(null, "file");
+ if (lname == null) {
+ Slog.w(TAG, "<library> without name at "
+ + parser.getPositionDescription());
+ } else if (lfile == null) {
+ Slog.w(TAG, "<library> without file at "
+ + parser.getPositionDescription());
+ } else {
+ //Log.i(TAG, "Got library " + lname + " in " + lfile);
+ mSharedLibraries.put(lname, lfile);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+
+ } else if ("feature".equals(name)) {
+ String fname = parser.getAttributeValue(null, "name");
+ if (fname == null) {
+ Slog.w(TAG, "<feature> without name at "
+ + parser.getPositionDescription());
+ } else {
+ //Log.i(TAG, "Got feature " + fname);
+ FeatureInfo fi = new FeatureInfo();
+ fi.name = fname;
+ mAvailableFeatures.put(fname, fi);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+
+ } else if ("allow-in-power-save".equals(name)) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<allow-in-power-save> without package at "
+ + parser.getPositionDescription());
+ } else {
+ mAllowInPowerSave.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ }
+ permReader.close();
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Got execption parsing permissions.", e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Got execption parsing permissions.", e);
+ }
+ }
+
+ void readPermission(XmlPullParser parser, String name)
+ throws IOException, XmlPullParserException {
+
+ name = name.intern();
+
+ PermissionEntry perm = mPermissions.get(name);
+ if (perm == null) {
+ perm = new PermissionEntry(name);
+ mPermissions.put(name, perm);
+ }
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if ("group".equals(tagName)) {
+ String gidStr = parser.getAttributeValue(null, "gid");
+ if (gidStr != null) {
+ int gid = Process.getGidForName(gidStr);
+ perm.gids = appendInt(perm.gids, gid);
+ } else {
+ Slog.w(TAG, "<group> without gid at "
+ + parser.getPositionDescription());
+ }
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 933046b..17268c3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -36,9 +36,6 @@
import android.app.IAppTask;
import android.app.admin.DevicePolicyManager;
import android.appwidget.AppWidgetManager;
-import android.content.DialogInterface.OnClickListener;
-import android.content.res.Resources;
-import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.os.BatteryStats;
import android.os.PersistableBundle;
@@ -174,12 +171,8 @@
import android.os.UpdateLock;
import android.os.UserHandle;
import android.provider.Settings;
-import android.text.Spannable;
-import android.text.SpannableString;
import android.text.format.DateUtils;
import android.text.format.Time;
-import android.text.style.DynamicDrawableSpan;
-import android.text.style.ImageSpan;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
@@ -193,7 +186,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
-import android.widget.TextView;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3cbc6e2..5c5e3e3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -365,6 +365,20 @@
}
}
+ public void noteFlashlightOn() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteFlashlightOnLocked();
+ }
+ }
+
+ public void noteFlashlightOff() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteFlashlightOffLocked();
+ }
+ }
+
public void noteWifiRunning(WorkSource ws) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 416a6b1..142094f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -39,6 +39,7 @@
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -111,6 +112,7 @@
import android.os.IPowerManager;
import android.os.Message;
import android.os.MessageQueue.IdleHandler;
+import android.os.PowerManagerInternal;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -119,6 +121,8 @@
import android.telephony.TelephonyManager;
import android.text.format.Formatter;
import android.text.format.Time;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.NtpTrustedTime;
@@ -133,6 +137,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -153,7 +159,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import libcore.io.IoUtils;
@@ -240,35 +245,43 @@
private IConnectivityManager mConnManager;
private INotificationManager mNotifManager;
+ private PowerManagerInternal mPowerManagerInternal;
private final Object mRulesLock = new Object();
private volatile boolean mScreenOn;
private volatile boolean mRestrictBackground;
+ private volatile boolean mRestrictPower;
private final boolean mSuppressDefaultPolicy;
/** Defined network policies. */
- private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
+ private final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<
+ NetworkTemplate, NetworkPolicy>();
/** Currently active network rules for ifaces. */
- private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
+ private final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<
+ NetworkPolicy, String[]>();
/** Defined UID policies. */
- private SparseIntArray mUidPolicy = new SparseIntArray();
+ private final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
- private SparseIntArray mUidRules = new SparseIntArray();
+ private final SparseIntArray mUidRules = new SparseIntArray();
+
+ /** UIDs that have been white-listed to always be able to have network access in
+ * power save mode. */
+ private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
/** Set of ifaces that are metered. */
private HashSet<String> mMeteredIfaces = Sets.newHashSet();
/** Set of over-limit templates that have been notified. */
- private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
+ private final HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
/** Set of currently active {@link Notification} tags. */
- private HashSet<String> mActiveNotifs = Sets.newHashSet();
+ private final HashSet<String> mActiveNotifs = Sets.newHashSet();
/** Foreground at both UID and PID granularity. */
- private SparseBooleanArray mUidForeground = new SparseBooleanArray();
- private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
+ private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
+ private final SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
SparseBooleanArray>();
private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
@@ -328,12 +341,42 @@
return;
}
+ final PackageManager pm = mContext.getPackageManager();
+
synchronized (mRulesLock) {
+ SystemConfig sysConfig = SystemConfig.getInstance();
+ ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
+ for (int i=0; i<allowPower.size(); i++) {
+ String pkg = allowPower.valueAt(i);
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+ if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ synchronized (mRulesLock) {
+ if (mRestrictPower != enabled) {
+ mRestrictPower = enabled;
+ updateRulesForGlobalChangeLocked(true);
+ }
+ }
+ }
+ });
+ mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+
// read policy from disk
readPolicyLocked();
- if (mRestrictBackground) {
- updateRulesForRestrictBackgroundLocked();
+ if (mRestrictBackground || mRestrictPower) {
+ updateRulesForGlobalChangeLocked(true);
updateNotificationsLocked();
}
}
@@ -482,7 +525,7 @@
// Update global restrict for new user
synchronized (mRulesLock) {
- updateRulesForRestrictBackgroundLocked();
+ updateRulesForGlobalChangeLocked(true);
}
}
};
@@ -633,7 +676,8 @@
// examine stats for each active policy
final long currentTime = currentTimeMillis();
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// ignore policies that aren't relevant to user
if (!isTemplateRelevant(policy.template)) continue;
if (!policy.hasCycle()) continue;
@@ -912,7 +956,8 @@
// completely, which is currently rare case.
final long currentTime = currentTimeMillis();
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// shortcut when policy has no limit
if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) {
setNetworkTemplateEnabled(policy.template, true);
@@ -978,29 +1023,41 @@
return;
}
+ // If we are in restrict power mode, we want to treat all interfaces
+ // as metered, to restrict access to the network by uid. However, we
+ // will not have a bandwidth limit. Also only do this if restrict
+ // background data use is *not* enabled, since that takes precendence
+ // use over those networks can have a cost associated with it).
+ final boolean powerSave = mRestrictPower && !mRestrictBackground;
+
// first, derive identity for all connected networks, which can be used
// to match against templates.
- final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
+ final ArrayMap<NetworkIdentity, String> networks = new ArrayMap();
+ final ArraySet<String> connIfaces = new ArraySet<String>();
for (NetworkState state : states) {
// stash identity and iface away for later use
if (state.networkInfo.isConnected()) {
final String iface = state.linkProperties.getInterfaceName();
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
networks.put(ident, iface);
+ if (powerSave) {
+ connIfaces.add(iface);
+ }
}
}
// build list of rules and ifaces to enforce them against
mNetworkRules.clear();
final ArrayList<String> ifaceList = Lists.newArrayList();
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// collect all active ifaces that match this template
ifaceList.clear();
- for (Map.Entry<NetworkIdentity, String> entry : networks.entrySet()) {
- final NetworkIdentity ident = entry.getKey();
+ for (int j = networks.size()-1; j >= 0; j--) {
+ final NetworkIdentity ident = networks.keyAt(j);
if (policy.template.matches(ident)) {
- final String iface = entry.getValue();
+ final String iface = networks.valueAt(j);
ifaceList.add(iface);
}
}
@@ -1017,8 +1074,9 @@
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
final long currentTime = currentTimeMillis();
- for (NetworkPolicy policy : mNetworkRules.keySet()) {
- final String[] ifaces = mNetworkRules.get(policy);
+ for (int i = mNetworkRules.size()-1; i >= 0; i--) {
+ final NetworkPolicy policy = mNetworkRules.keyAt(i);
+ final String[] ifaces = mNetworkRules.valueAt(i);
final long start;
final long totalBytes;
@@ -1063,6 +1121,9 @@
removeInterfaceQuota(iface);
setInterfaceQuota(iface, quotaBytes);
newMeteredIfaces.add(iface);
+ if (powerSave) {
+ connIfaces.remove(iface);
+ }
}
}
@@ -1075,6 +1136,13 @@
}
}
+ for (int i = connIfaces.size()-1; i >= 0; i--) {
+ String iface = connIfaces.valueAt(i);
+ removeInterfaceQuota(iface);
+ setInterfaceQuota(iface, Long.MAX_VALUE);
+ newMeteredIfaces.add(iface);
+ }
+
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
// remove quota on any trailing interfaces
@@ -1108,9 +1176,10 @@
// examine to see if any policy is defined for active mobile
boolean mobileDefined = false;
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
- if (policy.template.matches(probeIdent)) {
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ if (mNetworkPolicy.valueAt(i).template.matches(probeIdent)) {
mobileDefined = true;
+ break;
}
}
@@ -1226,7 +1295,7 @@
final int policy = readIntAttribute(in, ATTR_POLICY);
if (UserHandle.isApp(uid)) {
- setUidPolicyUnchecked(uid, policy, false);
+ setUidPolicyUncheckedLocked(uid, policy, false);
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
@@ -1237,7 +1306,7 @@
// TODO: set for other users during upgrade
final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
if (UserHandle.isApp(uid)) {
- setUidPolicyUnchecked(uid, policy, false);
+ setUidPolicyUncheckedLocked(uid, policy, false);
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
@@ -1289,7 +1358,8 @@
writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
// write all known network policies
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ for (int i = 0; i < mNetworkPolicy.size(); i++) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
final NetworkTemplate template = policy.template;
out.startTag(null, TAG_NETWORK_POLICY);
@@ -1346,24 +1416,59 @@
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
- setUidPolicyUnchecked(uid, policy, true);
+ synchronized (mRulesLock) {
+ final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+ if (oldPolicy != policy) {
+ setUidPolicyUncheckedLocked(uid, policy, true);
+ }
+ }
}
- private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
- final int oldPolicy;
- synchronized (mRulesLock) {
- oldPolicy = getUidPolicy(uid);
- mUidPolicy.put(uid, policy);
+ @Override
+ public void addUidPolicy(int uid, int policy) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- // uid policy changed, recompute rules and persist policy.
- updateRulesForUidLocked(uid);
- if (persist) {
- writePolicyLocked();
+ if (!UserHandle.isApp(uid)) {
+ throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+ }
+
+ synchronized (mRulesLock) {
+ final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+ policy |= oldPolicy;
+ if (oldPolicy != policy) {
+ setUidPolicyUncheckedLocked(uid, policy, true);
}
}
}
@Override
+ public void removeUidPolicy(int uid, int policy) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ if (!UserHandle.isApp(uid)) {
+ throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+ }
+
+ synchronized (mRulesLock) {
+ final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+ policy = oldPolicy & ~policy;
+ if (oldPolicy != policy) {
+ setUidPolicyUncheckedLocked(uid, policy, true);
+ }
+ }
+ }
+
+ private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
+ mUidPolicy.put(uid, policy);
+
+ // uid policy changed, recompute rules and persist policy.
+ updateRulesForUidLocked(uid);
+ if (persist) {
+ writePolicyLocked();
+ }
+ }
+
+ @Override
public int getUidPolicy(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
@@ -1389,6 +1494,20 @@
return uids;
}
+ @Override
+ public int[] getPowerSaveAppIdWhitelist() {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ synchronized (mRulesLock) {
+ int size = mPowerSaveWhitelistAppIds.size();
+ int[] appids = new int[size];
+ for (int i = 0; i < size; i++) {
+ appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
+ }
+ return appids;
+ }
+ }
+
/**
* Remove any policies associated with given {@link UserHandle}, persisting
* if any changes are made.
@@ -1515,7 +1634,7 @@
maybeRefreshTrustedTime();
synchronized (mRulesLock) {
mRestrictBackground = restrictBackground;
- updateRulesForRestrictBackgroundLocked();
+ updateRulesForGlobalChangeLocked(false);
updateNotificationsLocked();
writePolicyLocked();
}
@@ -1534,7 +1653,8 @@
}
private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ NetworkPolicy policy = mNetworkPolicy.valueAt(i);
if (policy.template.matches(ident)) {
return policy;
}
@@ -1623,8 +1743,8 @@
synchronized (mRulesLock) {
if (argSet.contains("--unsnooze")) {
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
- policy.clearSnooze();
+ for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+ mNetworkPolicy.valueAt(i).clearSnooze();
}
updateNetworkEnabledLocked();
@@ -1637,10 +1757,11 @@
}
fout.print("Restrict background: "); fout.println(mRestrictBackground);
+ fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.println("Network policies:");
fout.increaseIndent();
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
- fout.println(policy.toString());
+ for (int i = 0; i < mNetworkPolicy.size(); i++) {
+ fout.println(mNetworkPolicy.valueAt(i).toString());
}
fout.decreaseIndent();
@@ -1658,6 +1779,20 @@
}
fout.decreaseIndent();
+ size = mPowerSaveWhitelistAppIds.size();
+ if (size > 0) {
+ fout.println("Power save whitelist app ids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
+ fout.print(": ");
+ fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidForeground, knownUids);
collectKeys(mUidRules, knownUids);
@@ -1753,9 +1888,10 @@
}
/**
- * Update rules that might be changed by {@link #mRestrictBackground} value.
+ * Update rules that might be changed by {@link #mRestrictBackground}
+ * or {@link #mRestrictPower} value.
*/
- private void updateRulesForRestrictBackgroundLocked() {
+ private void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
final PackageManager pm = mContext.getPackageManager();
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -1774,6 +1910,11 @@
// limit data usage for some internal system services
updateRulesForUidLocked(android.os.Process.MEDIA_UID);
updateRulesForUidLocked(android.os.Process.DRM_UID);
+
+ // If the set of restricted networks may have changed, re-evaluate those.
+ if (restrictedNetworksChanged) {
+ updateNetworkRulesLocked();
+ }
}
private static boolean isUidValidForRules(int uid) {
@@ -1797,10 +1938,20 @@
if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
// uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED;
- }
- if (!uidForeground && mRestrictBackground) {
- // uid in background, and global background disabled
- uidRules = RULE_REJECT_METERED;
+ } else if (mRestrictBackground) {
+ if (!uidForeground) {
+ // uid in background, and global background disabled
+ uidRules = RULE_REJECT_METERED;
+ }
+ } else if (mRestrictPower) {
+ final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
+ if (!whitelisted && !uidForeground
+ && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
+ // uid is in background, restrict power use mode is on (so we want to
+ // restrict all background network access), and this uid is not on the
+ // white list of those allowed background access.
+ uidRules = RULE_REJECT_METERED;
+ }
}
// TODO: only dispatch when rules actually change
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cac27bc..cf32be9 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -36,6 +36,7 @@
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
+import android.util.ArrayMap;
import com.android.internal.R;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
@@ -50,6 +51,7 @@
import com.android.server.IntentResolver;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
import com.android.server.Watchdog;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -391,17 +393,20 @@
final Settings mSettings;
boolean mRestoredSettings;
- // Group-ids that are given to all packages as read from etc/permissions/*.xml.
- int[] mGlobalGids;
+ // System configuration read by SystemConfig.
+ final int[] mGlobalGids;
+ final SparseArray<HashSet<String>> mSystemPermissions;
+ final HashMap<String, FeatureInfo> mAvailableFeatures;
- // These are the built-in uid -> permission mappings that were read from the
- // etc/permissions.xml file.
- final SparseArray<HashSet<String>> mSystemPermissions =
- new SparseArray<HashSet<String>>();
+ // If mac_permissions.xml was found for seinfo labeling.
+ boolean mFoundPolicyFile;
- static final class SharedLibraryEntry {
- final String path;
- final String apk;
+ // If a recursive restorecon of /data/data/<pkg> is needed.
+ private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
+
+ public static final class SharedLibraryEntry {
+ public final String path;
+ public final String apk;
SharedLibraryEntry(String _path, String _apk) {
path = _path;
@@ -409,21 +414,9 @@
}
}
- // These are the built-in shared libraries that were read from the
- // etc/permissions.xml file.
- final HashMap<String, SharedLibraryEntry> mSharedLibraries
- = new HashMap<String, SharedLibraryEntry>();
-
- // These are the features this devices supports that were read from the
- // etc/permissions.xml file.
- final HashMap<String, FeatureInfo> mAvailableFeatures =
- new HashMap<String, FeatureInfo>();
-
- // If mac_permissions.xml was found for seinfo labeling.
- boolean mFoundPolicyFile;
-
- // If a recursive restorecon of /data/data/<pkg> is needed.
- private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
+ // Currently known shared libraries.
+ final HashMap<String, SharedLibraryEntry> mSharedLibraries =
+ new HashMap<String, SharedLibraryEntry>();
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
@@ -1331,6 +1324,11 @@
getDefaultDisplayMetrics(context, mMetrics);
+ SystemConfig systemConfig = SystemConfig.getInstance();
+ mGlobalGids = systemConfig.getGlobalGids();
+ mSystemPermissions = systemConfig.getSystemPermissions();
+ mAvailableFeatures = systemConfig.getAvailableFeatures();
+
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
@@ -1352,12 +1350,26 @@
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
- // Read permissions and features from system
- readPermissions(Environment.buildPath(
- Environment.getRootDirectory(), "etc", "permissions"), false);
- // Only read features from OEM
- readPermissions(Environment.buildPath(
- Environment.getOemDirectory(), "etc", "permissions"), true);
+ // Propagate permission configuration in to package manager.
+ ArrayMap<String, SystemConfig.PermissionEntry> permConfig
+ = systemConfig.getPermissions();
+ for (int i=0; i<permConfig.size(); i++) {
+ SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
+ BasePermission bp = mSettings.mPermissions.get(perm.name);
+ if (bp == null) {
+ bp = new BasePermission(perm.name, null, BasePermission.TYPE_BUILTIN);
+ mSettings.mPermissions.put(perm.name, bp);
+ }
+ if (perm.gids != null) {
+ bp.gids = appendInts(bp.gids, perm.gids);
+ }
+ }
+
+ ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
+ for (int i=0; i<libConfig.size(); i++) {
+ mSharedLibraries.put(libConfig.keyAt(i),
+ new SharedLibraryEntry(libConfig.valueAt(i), null));
+ }
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
@@ -1822,198 +1834,6 @@
mSettings.removePackageLPw(ps.name);
}
- void readPermissions(File libraryDir, boolean onlyFeatures) {
- // Read permissions from .../etc/permission directory.
- if (!libraryDir.exists() || !libraryDir.isDirectory()) {
- Slog.w(TAG, "No directory " + libraryDir + ", skipping");
- return;
- }
- if (!libraryDir.canRead()) {
- Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
- return;
- }
-
- // Iterate over the files in the directory and scan .xml files
- for (File f : libraryDir.listFiles()) {
- // We'll read platform.xml last
- if (f.getPath().endsWith("etc/permissions/platform.xml")) {
- continue;
- }
-
- if (!f.getPath().endsWith(".xml")) {
- Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
- continue;
- }
- if (!f.canRead()) {
- Slog.w(TAG, "Permissions library file " + f + " cannot be read");
- continue;
- }
-
- readPermissionsFromXml(f, onlyFeatures);
- }
-
- // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
- final File permFile = new File(Environment.getRootDirectory(),
- "etc/permissions/platform.xml");
- readPermissionsFromXml(permFile, onlyFeatures);
- }
-
- private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
- FileReader permReader = null;
- try {
- permReader = new FileReader(permFile);
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
- return;
- }
-
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(permReader);
-
- XmlUtils.beginDocument(parser, "permissions");
-
- while (true) {
- XmlUtils.nextElement(parser);
- if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
- break;
- }
-
- String name = parser.getName();
- if ("group".equals(name) && !onlyFeatures) {
- String gidStr = parser.getAttributeValue(null, "gid");
- if (gidStr != null) {
- int gid = Process.getGidForName(gidStr);
- mGlobalGids = appendInt(mGlobalGids, gid);
- } else {
- Slog.w(TAG, "<group> without gid at "
- + parser.getPositionDescription());
- }
-
- XmlUtils.skipCurrentTag(parser);
- continue;
- } else if ("permission".equals(name) && !onlyFeatures) {
- String perm = parser.getAttributeValue(null, "name");
- if (perm == null) {
- Slog.w(TAG, "<permission> without name at "
- + parser.getPositionDescription());
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
- perm = perm.intern();
- readPermission(parser, perm);
-
- } else if ("assign-permission".equals(name) && !onlyFeatures) {
- String perm = parser.getAttributeValue(null, "name");
- if (perm == null) {
- Slog.w(TAG, "<assign-permission> without name at "
- + parser.getPositionDescription());
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
- String uidStr = parser.getAttributeValue(null, "uid");
- if (uidStr == null) {
- Slog.w(TAG, "<assign-permission> without uid at "
- + parser.getPositionDescription());
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
- int uid = Process.getUidForName(uidStr);
- if (uid < 0) {
- Slog.w(TAG, "<assign-permission> with unknown uid \""
- + uidStr + "\" at "
- + parser.getPositionDescription());
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
- perm = perm.intern();
- HashSet<String> perms = mSystemPermissions.get(uid);
- if (perms == null) {
- perms = new HashSet<String>();
- mSystemPermissions.put(uid, perms);
- }
- perms.add(perm);
- XmlUtils.skipCurrentTag(parser);
-
- } else if ("library".equals(name) && !onlyFeatures) {
- String lname = parser.getAttributeValue(null, "name");
- String lfile = parser.getAttributeValue(null, "file");
- if (lname == null) {
- Slog.w(TAG, "<library> without name at "
- + parser.getPositionDescription());
- } else if (lfile == null) {
- Slog.w(TAG, "<library> without file at "
- + parser.getPositionDescription());
- } else {
- //Log.i(TAG, "Got library " + lname + " in " + lfile);
- mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null));
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("feature".equals(name)) {
- String fname = parser.getAttributeValue(null, "name");
- if (fname == null) {
- Slog.w(TAG, "<feature> without name at "
- + parser.getPositionDescription());
- } else {
- //Log.i(TAG, "Got feature " + fname);
- FeatureInfo fi = new FeatureInfo();
- fi.name = fname;
- mAvailableFeatures.put(fname, fi);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else {
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
-
- }
- permReader.close();
- } catch (XmlPullParserException e) {
- Slog.w(TAG, "Got execption parsing permissions.", e);
- } catch (IOException e) {
- Slog.w(TAG, "Got execption parsing permissions.", e);
- }
- }
-
- void readPermission(XmlPullParser parser, String name)
- throws IOException, XmlPullParserException {
-
- name = name.intern();
-
- BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
- mSettings.mPermissions.put(name, bp);
- }
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if ("group".equals(tagName)) {
- String gidStr = parser.getAttributeValue(null, "gid");
- if (gidStr != null) {
- int gid = Process.getGidForName(gidStr);
- bp.gids = appendInt(bp.gids, gid);
- } else {
- Slog.w(TAG, "<group> without gid at "
- + parser.getPositionDescription());
- }
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
static int[] appendInts(int[] cur, int[] add) {
if (add == null) return cur;
if (cur == null) return add;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c78249b..81302b9 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -346,31 +346,21 @@
*/
public static boolean assignSeinfoValue(PackageParser.Package pkg) {
- /*
- * Non system installed apps should be treated the same. This
- * means that any post-loaded apk will be assigned the default
- * tag, if one exists in the policy, else null, without respect
- * to the signing key.
- */
- if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||
- ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
+ // We just want one of the signatures to match.
+ for (Signature s : pkg.mSignatures) {
+ if (s == null)
+ continue;
- // We just want one of the signatures to match.
- for (Signature s : pkg.mSignatures) {
- if (s == null)
- continue;
+ Policy policy = sSigSeinfo.get(s);
+ if (policy != null) {
+ String seinfo = policy.checkPolicy(pkg.packageName);
+ if (seinfo != null) {
+ pkg.applicationInfo.seinfo = seinfo;
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "package (" + pkg.packageName +
+ ") labeled with seinfo=" + seinfo);
- Policy policy = sSigSeinfo.get(s);
- if (policy != null) {
- String seinfo = policy.checkPolicy(pkg.packageName);
- if (seinfo != null) {
- pkg.applicationInfo.seinfo = seinfo;
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "package (" + pkg.packageName +
- ") labeled with seinfo=" + seinfo);
-
- return true;
- }
+ return true;
}
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0d05c5f..52ca098 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -404,6 +404,9 @@
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
try {
+ Slog.i(TAG, "Reading configuration...");
+ SystemConfig.getInstance();
+
Slog.i(TAG, "Scheduling Policy");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
diff --git a/telecomm/java/android/telecomm/CallVideoClient.java b/telecomm/java/android/telecomm/CallVideoClient.java
index 9e3c48d..76b28fa 100644
--- a/telecomm/java/android/telecomm/CallVideoClient.java
+++ b/telecomm/java/android/telecomm/CallVideoClient.java
@@ -17,6 +17,7 @@
package android.telecomm;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -66,22 +67,22 @@
*/
public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
- private static final int MSG_ON_RECEIVE_SESSION_MODIFY_REQUEST = 1;
- private static final int MSG_ON_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
- private static final int MSG_ON_CALL_SESSION_EVENT = 3;
- private static final int MSG_ON_UPDATED_PEER_DIMENSIONS = 4;
- private static final int MSG_ON_UPDATE_CALL_DATA_USAGE = 5;
- private static final int MSG_ON_CAMERA_CAPABILITIES_CHANGE = 6;
+ private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
+ private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
+ private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
+ private static final int MSG_UPDATE_PEER_DIMENSIONS = 4;
+ private static final int MSG_UPDATE_CALL_DATA_USAGE = 5;
+ private static final int MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE = 6;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_ON_RECEIVE_SESSION_MODIFY_REQUEST:
+ case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
onReceiveSessionModifyRequest((VideoCallProfile) msg.obj);
break;
- case MSG_ON_RECEIVE_SESSION_MODIFY_RESPONSE: {
+ case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
int status = (int) args.arg1;
@@ -95,25 +96,25 @@
}
break;
}
- case MSG_ON_CALL_SESSION_EVENT:
- onCallSessionEvent((int) msg.obj);
+ case MSG_HANDLE_CALL_SESSION_EVENT:
+ onHandleCallSessionEvent((int) msg.obj);
break;
- case MSG_ON_UPDATED_PEER_DIMENSIONS: {
+ case MSG_UPDATE_PEER_DIMENSIONS: {
SomeArgs args = (SomeArgs) msg.obj;
try {
int width = (int) args.arg1;
int height = (int) args.arg2;
- onUpdatedPeerDimensions(width, height);
+ onUpdatePeerDimensions(width, height);
} finally {
args.recycle();
}
break;
}
- case MSG_ON_UPDATE_CALL_DATA_USAGE:
+ case MSG_UPDATE_CALL_DATA_USAGE:
onUpdateCallDataUsage(msg.arg1);
break;
- case MSG_ON_CAMERA_CAPABILITIES_CHANGE:
- onCameraCapabilitiesChange((CallCameraCapabilities) msg.obj);
+ case MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE:
+ onHandleCameraCapabilitiesChange((CallCameraCapabilities) msg.obj);
break;
default:
break;
@@ -126,42 +127,42 @@
*/
private final class CallVideoClientBinder extends ICallVideoClient.Stub {
@Override
- public void onReceiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
- mHandler.obtainMessage(MSG_ON_RECEIVE_SESSION_MODIFY_REQUEST,
+ public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
+ mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,
videoCallProfile).sendToTarget();
}
@Override
- public void onReceiveSessionModifyResponse(int status,
+ public void receiveSessionModifyResponse(int status,
VideoCallProfile requestProfile, VideoCallProfile responseProfile) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = status;
args.arg2 = requestProfile;
args.arg3 = responseProfile;
- mHandler.obtainMessage(MSG_ON_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
+ mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
}
@Override
- public void onCallSessionEvent(int event) {
- mHandler.obtainMessage(MSG_ON_CALL_SESSION_EVENT, event).sendToTarget();
+ public void handleCallSessionEvent(int event) {
+ mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget();
}
@Override
- public void onUpdatedPeerDimensions(int width, int height) {
+ public void updatePeerDimensions(int width, int height) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = width;
args.arg2 = height;
- mHandler.obtainMessage(MSG_ON_UPDATED_PEER_DIMENSIONS, args).sendToTarget();
+ mHandler.obtainMessage(MSG_UPDATE_PEER_DIMENSIONS, args).sendToTarget();
}
@Override
- public void onUpdateCallDataUsage(int dataUsage) {
- mHandler.obtainMessage(MSG_ON_UPDATE_CALL_DATA_USAGE, dataUsage).sendToTarget();
+ public void updateCallDataUsage(int dataUsage) {
+ mHandler.obtainMessage(MSG_UPDATE_CALL_DATA_USAGE, dataUsage).sendToTarget();
}
@Override
- public void onCameraCapabilitiesChange(CallCameraCapabilities cameraCapabilities) {
- mHandler.obtainMessage(MSG_ON_CAMERA_CAPABILITIES_CHANGE,
+ public void handleCameraCapabilitiesChange(CallCameraCapabilities cameraCapabilities) {
+ mHandler.obtainMessage(MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE,
cameraCapabilities).sendToTarget();
}
}
@@ -173,21 +174,19 @@
}
/**
- * Retrieves the binder.
- *
- * @return The binder.
+ * Returns binder object which can be used across IPC methods.
* @hide
*/
- public final CallVideoClientBinder getBinder() {
+ public final IBinder getBinder() {
return mBinder;
}
/**
* Called when a session modification request is received from the remote device.
- * The remote request is sent via {@link CallVideoProvider#sendSessionModifyRequest}.
+ * The remote request is sent via {@link CallVideoProvider#onSendSessionModifyRequest}.
* The InCall UI is responsible for potentially prompting the user whether they wish to accept
* the new call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a
- * video call) and should call {@link CallVideoProvider#sendSessionModifyResponse} to indicate
+ * video call) and should call {@link CallVideoProvider#onSendSessionModifyResponse} to indicate
* the video settings the user has agreed to.
*
* @param videoCallProfile The requested video call profile.
@@ -197,7 +196,7 @@
/**
* Called when a response to a session modification request is received from the remote device.
* The remote InCall UI sends the response using
- * {@link CallVideoProvider#sendSessionModifyResponse}.
+ * {@link CallVideoProvider#onSendSessionModifyResponse}.
*
* @param status Status of the session modify request. Valid values are
* {@link CallVideoClient#SESSION_MODIFY_REQUEST_SUCCESS},
@@ -219,7 +218,7 @@
*
* @param event The event.
*/
- public abstract void onCallSessionEvent(int event);
+ public abstract void onHandleCallSessionEvent(int event);
/**
* Handles a change to the video dimensions from the remote caller (peer). This could happen
@@ -228,7 +227,7 @@
* @param width The updated peer video width.
* @param height The updated peer video height.
*/
- public abstract void onUpdatedPeerDimensions(int width, int height);
+ public abstract void onUpdatePeerDimensions(int width, int height);
/**
* Handles an update to the total data used for the current session.
@@ -242,6 +241,6 @@
*
* @param callCameraCapabilities The changed camera capabilities.
*/
- public abstract void onCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities);
+ public abstract void onHandleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities);
}
diff --git a/telecomm/java/android/telecomm/CallVideoProvider.java b/telecomm/java/android/telecomm/CallVideoProvider.java
index 2f16112..2a04724 100644
--- a/telecomm/java/android/telecomm/CallVideoProvider.java
+++ b/telecomm/java/android/telecomm/CallVideoProvider.java
@@ -17,22 +17,26 @@
package android.telecomm;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
+import android.os.RemoteException;
import android.view.Surface;
+import com.android.internal.telecomm.ICallVideoClient;
import com.android.internal.telecomm.ICallVideoProvider;
public abstract class CallVideoProvider {
- private static final int MSG_SET_CAMERA = 1;
- private static final int MSG_SET_PREVIEW_SURFACE = 2;
- private static final int MSG_SET_DISPLAY_SURFACE = 3;
- private static final int MSG_SET_DEVICE_ORIENTATION = 4;
- private static final int MSG_SET_ZOOM = 5;
- private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 6;
- private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 7;
- private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 8;
- private static final int MSG_REQUEST_CALL_DATA_USAGE = 9;
- private static final int MSG_SET_PAUSE_IMAGE = 10;
+ private static final int MSG_SET_CALL_VIDEO_CLIENT = 1;
+ private static final int MSG_SET_CAMERA = 2;
+ private static final int MSG_SET_PREVIEW_SURFACE = 3;
+ private static final int MSG_SET_DISPLAY_SURFACE = 4;
+ private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+ private static final int MSG_SET_ZOOM = 6;
+ private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+ private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+ private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+ private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+ private static final int MSG_SET_PAUSE_IMAGE = 11;
/**
* Default handler used to consolidate binder method calls onto a single thread.
@@ -41,35 +45,45 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
+ case MSG_SET_CALL_VIDEO_CLIENT:
+ try {
+ ICallVideoClient callVideoClient =
+ ICallVideoClient.Stub.asInterface((IBinder) msg.obj);
+ RemoteCallVideoClient remoteCallVideoClient =
+ new RemoteCallVideoClient(callVideoClient);
+ onSetCallVideoClient(remoteCallVideoClient);
+ } catch (RemoteException ignored) {
+ }
+ break;
case MSG_SET_CAMERA:
- setCamera((String) msg.obj);
+ onSetCamera((String) msg.obj);
break;
case MSG_SET_PREVIEW_SURFACE:
- setPreviewSurface((Surface) msg.obj);
+ onSetPreviewSurface((Surface) msg.obj);
break;
case MSG_SET_DISPLAY_SURFACE:
- setDisplaySurface((Surface) msg.obj);
+ onSetDisplaySurface((Surface) msg.obj);
break;
case MSG_SET_DEVICE_ORIENTATION:
- setDeviceOrientation(msg.arg1);
+ onSetDeviceOrientation(msg.arg1);
break;
case MSG_SET_ZOOM:
- setZoom((Float) msg.obj);
+ onSetZoom((Float) msg.obj);
break;
case MSG_SEND_SESSION_MODIFY_REQUEST:
- sendSessionModifyRequest((VideoCallProfile) msg.obj);
+ onSendSessionModifyRequest((VideoCallProfile) msg.obj);
break;
case MSG_SEND_SESSION_MODIFY_RESPONSE:
- sendSessionModifyResponse((VideoCallProfile) msg.obj);
+ onSendSessionModifyResponse((VideoCallProfile) msg.obj);
break;
case MSG_REQUEST_CAMERA_CAPABILITIES:
- requestCameraCapabilities();
+ onRequestCameraCapabilities();
break;
case MSG_REQUEST_CALL_DATA_USAGE:
- requestCallDataUsage();
+ onRequestCallDataUsage();
break;
case MSG_SET_PAUSE_IMAGE:
- setPauseImage((String) msg.obj);
+ onSetPauseImage((String) msg.obj);
break;
default:
break;
@@ -81,6 +95,11 @@
* Default ICallVideoProvider implementation.
*/
private final class CallVideoProviderBinder extends ICallVideoProvider.Stub {
+ public void setCallVideoClient(IBinder callVideoClientBinder) {
+ mMessageHandler.obtainMessage(
+ MSG_SET_CALL_VIDEO_CLIENT, callVideoClientBinder).sendToTarget();
+ }
+
public void setCamera(String cameraId) {
mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
}
@@ -102,13 +121,13 @@
}
public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
- mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST,
- requestProfile).sendToTarget();
+ mMessageHandler.obtainMessage(
+ MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget();
}
public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
- mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_RESPONSE,
- responseProfile).sendToTarget();
+ mMessageHandler.obtainMessage(
+ MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
}
public void requestCameraCapabilities() {
@@ -140,11 +159,19 @@
}
/**
+ * Sets a remote interface for invoking callback methods in the InCallUI after performing
+ * telephony actions.
+ *
+ * @param callVideoClient The call video client.
+ */
+ public abstract void onSetCallVideoClient(RemoteCallVideoClient callVideoClient);
+
+ /**
* Sets the camera to be used for video recording in a video call.
*
* @param cameraId The id of the camera.
*/
- public abstract void setCamera(String cameraId);
+ public abstract void onSetCamera(String cameraId);
/**
* Sets the surface to be used for displaying a preview of what the user's camera is
@@ -153,14 +180,14 @@
*
* @param surface The surface.
*/
- public abstract void setPreviewSurface(Surface surface);
+ public abstract void onSetPreviewSurface(Surface surface);
/**
* Sets the surface to be used for displaying the video received from the remote device.
*
* @param surface The surface.
*/
- public abstract void setDisplaySurface(Surface surface);
+ public abstract void onSetDisplaySurface(Surface surface);
/**
* Sets the device orientation, in degrees. Assumes that a standard portrait orientation of the
@@ -168,14 +195,14 @@
*
* @param rotation The device orientation, in degrees.
*/
- public abstract void setDeviceOrientation(int rotation);
+ public abstract void onSetDeviceOrientation(int rotation);
/**
* Sets camera zoom ratio.
*
* @param value The camera zoom ratio.
*/
- public abstract void setZoom(float value);
+ public abstract void onSetZoom(float value);
/**
* Issues a request to modify the properties of the current session. The request is sent to
@@ -186,7 +213,7 @@
*
* @param requestProfile The requested call video properties.
*/
- public abstract void sendSessionModifyRequest(VideoCallProfile requestProfile);
+ public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile);
/**
* Provides a response to a request to change the current call session video
@@ -198,21 +225,21 @@
*
* @param responseProfile The response call video properties.
*/
- public abstract void sendSessionModifyResponse(VideoCallProfile responseProfile);
+ public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile);
/**
* Issues a request to the video provider to retrieve the camera capabilities.
* Camera capabilities are reported back to the caller via
- * {@link CallVideoClient#onCameraCapabilitiesChange(CallCameraCapabilities)}.
+ * {@link CallVideoClient#onHandleCameraCapabilitiesChange(CallCameraCapabilities)}.
*/
- public abstract void requestCameraCapabilities();
+ public abstract void onRequestCameraCapabilities();
/**
* Issues a request to the video telephony framework to retrieve the cumulative data usage for
* the current call. Data usage is reported back to the caller via
* {@link CallVideoClient#onUpdateCallDataUsage}.
*/
- public abstract void requestCallDataUsage();
+ public abstract void onRequestCallDataUsage();
/**
* Provides the video telephony framework with the URI of an image to be displayed to remote
@@ -220,5 +247,5 @@
*
* @param uri URI of image to display.
*/
- public abstract void setPauseImage(String uri);
+ public abstract void onSetPauseImage(String uri);
}
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoClient.java b/telecomm/java/android/telecomm/RemoteCallVideoClient.java
new file mode 100644
index 0000000..f0a3afc
--- /dev/null
+++ b/telecomm/java/android/telecomm/RemoteCallVideoClient.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecomm;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telecomm.CallCameraCapabilities;
+import android.telecomm.VideoCallProfile;
+
+import com.android.internal.telecomm.ICallVideoClient;
+
+public class RemoteCallVideoClient implements IBinder.DeathRecipient {
+ private final ICallVideoClient mCallVideoClient;
+
+ RemoteCallVideoClient(ICallVideoClient callVideoProvider) throws RemoteException {
+ mCallVideoClient = callVideoProvider;
+ mCallVideoClient.asBinder().linkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ mCallVideoClient.asBinder().unlinkToDeath(this, 0);
+ }
+
+ public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile)
+ throws RemoteException {
+ mCallVideoClient.receiveSessionModifyRequest(videoCallProfile);
+ }
+
+ public void receiveSessionModifyResponse(int status, VideoCallProfile requestedProfile,
+ VideoCallProfile responseProfile) throws RemoteException {
+ mCallVideoClient.receiveSessionModifyResponse(status, requestedProfile, responseProfile);
+ }
+
+ public void handleCallSessionEvent(int event) throws RemoteException {
+ mCallVideoClient.handleCallSessionEvent(event);
+ }
+
+ public void updatePeerDimensions(int width, int height) throws RemoteException {
+ mCallVideoClient.updatePeerDimensions(width, height);
+ }
+
+ public void updateCallDataUsage(int dataUsage) throws RemoteException {
+ mCallVideoClient.updateCallDataUsage(dataUsage);
+ }
+
+ public void handleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities)
+ throws RemoteException {
+ mCallVideoClient.handleCameraCapabilitiesChange(callCameraCapabilities);
+ }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
index 872085a..4a226a9 100644
--- a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
+++ b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
@@ -18,10 +18,11 @@
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.Surface;
+import com.android.internal.telecomm.ICallVideoClient;
import com.android.internal.telecomm.ICallVideoProvider;
-
public class RemoteCallVideoProvider implements IBinder.DeathRecipient {
private final ICallVideoProvider mCallVideoProvider;
@@ -35,12 +36,47 @@
mCallVideoProvider.asBinder().unlinkToDeath(this, 0);
}
- /**
- * Sets the camera to be used for video recording in a video call, using the binder.
- *
- * @param cameraId The id of the camera.
- */
+ public void setCallVideoClient(CallVideoClient callVideoClient) throws RemoteException {
+ mCallVideoProvider.setCallVideoClient(callVideoClient.getBinder());
+ }
+
public void setCamera(String cameraId) throws RemoteException {
mCallVideoProvider.setCamera(cameraId);
}
-}
+
+ public void setPreviewSurface(Surface surface) throws RemoteException {
+ mCallVideoProvider.setPreviewSurface(surface);
+ }
+
+ public void setDisplaySurface(Surface surface) throws RemoteException {
+ mCallVideoProvider.setDisplaySurface(surface);
+ }
+
+ public void setDeviceOrientation(int rotation) throws RemoteException {
+ mCallVideoProvider.setDeviceOrientation(rotation);
+ }
+
+ public void setZoom(float value) throws RemoteException {
+ mCallVideoProvider.setZoom(value);
+ }
+
+ public void sendSessionModifyRequest(VideoCallProfile requestProfile) throws RemoteException {
+ mCallVideoProvider.sendSessionModifyRequest(requestProfile);
+ }
+
+ public void sendSessionModifyResponse(VideoCallProfile responseProfile) throws RemoteException {
+ mCallVideoProvider.sendSessionModifyResponse(responseProfile);
+ }
+
+ public void requestCameraCapabilities() throws RemoteException {
+ mCallVideoProvider.requestCameraCapabilities();
+ }
+
+ public void requestCallDataUsage() throws RemoteException {
+ mCallVideoProvider.requestCallDataUsage();
+ }
+
+ public void onSetPauseImage(String uri) throws RemoteException {
+ mCallVideoProvider.setPauseImage(uri);
+ }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index a0abc28..6bb75be 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -1,17 +1,15 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 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
+ * 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.
+ * 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.telecomm;
@@ -62,14 +60,111 @@
@SystemApi
public ComponentName getDefaultPhoneApp() {
try {
- return getTelecommService().getDefaultPhoneApp();
+ if (isServiceConnected()) {
+ return getTelecommService().getDefaultPhoneApp();
+ }
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get the default phone app.", e);
}
return null;
}
+ /**
+ * Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
+ * states).
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isInAPhoneCall() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().isInAPhoneCall();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException attempting to get default phone app.", e);
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether there currently exists is a ringing incoming-call.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isRinging() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().isRinging();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException attempting to get ringing state of phone app.", e);
+ }
+ return false;
+ }
+
+ /**
+ * Ends an ongoing call. TODO(santoscordon): L-release - need to convert all invocations of
+ * ITelephony#endCall to use this method (clockwork & gearhead).
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean endCall() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().endCall();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#endCall", e);
+ }
+ return false;
+ }
+
+ /**
+ * If there is a ringing incoming call, this method accepts the call on behalf of the user.
+ * TODO(santoscordon): L-release - need to convert all invocation of
+ * ITelephony#answerRingingCall to use this method (clockwork & gearhead).
+ *
+ * @hide
+ */
+ @SystemApi
+ public void acceptRingingCall() {
+ try {
+ if (isServiceConnected()) {
+ getTelecommService().acceptRingingCall();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#acceptRingingCall", e);
+ }
+ }
+
+ /**
+ * Silences the ringer if a ringing call exists.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void silenceRinger() {
+ try {
+ if (isServiceConnected()) {
+ getTelecommService().silenceRinger();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#silenceRinger", e);
+ }
+ }
+
private ITelecommService getTelecommService() {
return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
}
+
+ private boolean isServiceConnected() {
+ boolean isConnected = getTelecommService() != null;
+ if (!isConnected) {
+ Log.w(TAG, "Telecomm Service not found.");
+ }
+ return isConnected;
+ }
}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl b/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
index 0a854a1..2689561 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
@@ -29,16 +29,16 @@
*/
oneway interface ICallVideoClient {
- void onReceiveSessionModifyRequest(in VideoCallProfile videoCallProfile);
+ void receiveSessionModifyRequest(in VideoCallProfile videoCallProfile);
- void onReceiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile,
+ void receiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile,
in VideoCallProfile responseProfile);
- void onCallSessionEvent(int event);
+ void handleCallSessionEvent(int event);
- void onUpdatedPeerDimensions(int width, int height);
+ void updatePeerDimensions(int width, int height);
- void onUpdateCallDataUsage(int dataUsage);
+ void updateCallDataUsage(int dataUsage);
- void onCameraCapabilitiesChange(in CallCameraCapabilities callCameraCapabilities);
+ void handleCameraCapabilitiesChange(in CallCameraCapabilities callCameraCapabilities);
}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl b/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
index f6587b7..860a431 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
@@ -19,12 +19,16 @@
import android.view.Surface;
import android.telecomm.VideoCallProfile;
+import com.android.internal.telecomm.ICallVideoClient;
+
/**
* Internal remote interface for a call video provider.
* @see android.telecomm.CallVideoProvider
* @hide
*/
oneway interface ICallVideoProvider {
+ void setCallVideoClient(IBinder callVideoClient);
+
void setCamera(String cameraId);
void setPreviewSurface(in Surface surface);
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 2ae5768..65389df 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -25,16 +25,6 @@
* {@hide}
*/
interface ITelecommService {
-
- /**
- * Silence the ringer if an incoming call is currently ringing.
- * (If vibrating, stop the vibrator also.)
- *
- * It's safe to call this if the ringer has already been silenced, or
- * even if there's no incoming call. (If so, this method will do nothing.)
- */
- void silenceRinger();
-
/**
* Brings the in-call screen to the foreground if there is an active call.
*
@@ -61,4 +51,33 @@
* Returns the component name of the default phone application.
*/
ComponentName getDefaultPhoneApp();
+
+ //
+ // Internal system apis relating to call management.
+ //
+
+ /**
+ * @see TelecommManager#silenceRinger
+ */
+ void silenceRinger();
+
+ /**
+ * @see TelecommManager#isInAPhoneCall
+ */
+ boolean isInAPhoneCall();
+
+ /**
+ * @see TelecomManager#isRinging
+ */
+ boolean isRinging();
+
+ /**
+ * @see TelecommManager#endCall
+ */
+ boolean endCall();
+
+ /**
+ * @see TelecommManager#acceptRingingCall
+ */
+ void acceptRingingCall();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 124a8ec..0e5b0e6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2793,6 +2793,25 @@
}
/**
+ * Set the CDMA subscription source.
+ * Used for device supporting both NV and RUIM for CDMA.
+ *
+ * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
+ * @return true on success; false on any failure.
+ * @hide
+ */
+ public boolean setCdmaSubscription(int subscriptionType) {
+ try {
+ return getITelephony().setCdmaSubscription(subscriptionType);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setCdmaSubscription RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "setCdmaSubscription NPE", ex);
+ }
+ return false;
+ }
+
+ /**
* Expose the rest of ITelephony to @SystemApi
*/
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 32929ed..f9375e4 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -47,6 +47,26 @@
int queryCallWaiting();
/**
+ * Retrieves the default CLIR setting.
+ */
+ int queryCLIR();
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ int queryCLIP();
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ int queryCOLR();
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ int queryCOLP();
+
+ /**
* Updates or retrieves the supplementary service configuration.
*/
int transact(in Bundle ssInfo);
@@ -67,6 +87,26 @@
int updateCallWaiting(boolean enable);
/**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ int updateCLIR(int clirMode);
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ int updateCLIP(boolean enable);
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ int updateCOLR(int presentation);
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ int updateCOLP(boolean enable);
+
+ /**
* Sets the listener.
*/
void setListener(in IImsUtListener listener);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index beee616..237e7f3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -606,6 +606,15 @@
boolean setPreferredNetworkType(int networkType);
/**
+ * Set the CDMA subscription source.
+ * Used for device supporting both NV and RUIM for CDMA.
+ *
+ * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
+ * @return true on success; false on any failure.
+ */
+ boolean setCdmaSubscription(int subscriptionType);
+
+ /**
* User enable/disable Mobile Data.
*
* @param enable true to turn on, else false
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
index 2ea5219..1bb6d0c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
@@ -22,6 +22,8 @@
import android.content.pm.ConfigurationInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.opengl.EGL14;
+import android.opengl.EGLDisplay;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
@@ -29,7 +31,7 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
-
+import android.view.MotionEvent;
import java.io.IOException;
import java.io.InputStream;
@@ -54,7 +56,8 @@
// 2.0-compatible
// context, and set an OpenGL ES 2.0-compatible renderer.
mGLSurfaceView.setEGLContextClientVersion(2);
- mGLSurfaceView.setRenderer(new GLES20TriangleRenderer(this));
+ mRenderer = new GLES20TriangleRenderer(this);
+ mGLSurfaceView.setRenderer(mRenderer);
} else {
throw new IllegalStateException("Can't find OGL ES2.0 context");
}
@@ -84,7 +87,17 @@
mGLSurfaceView.onPause();
}
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ Log.i("motion", event.toString());
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mRenderer.toggleDepthTest();
+ }
+ return true;
+ }
+
private GLSurfaceView mGLSurfaceView;
+ private GLES20TriangleRenderer mRenderer;
/*
* Copyright (C) 2009 The Android Open Source Project Licensed under the
@@ -99,7 +112,9 @@
*/
class GLES20TriangleRenderer implements GLSurfaceView.Renderer {
-
+ private final static int REPEAT_RECTANGLES = 10;
+ private boolean mDepthTestEnabled = true;
+ private final static int FRAME_REPEAT_TIMES = 1;
public GLES20TriangleRenderer(Context context) {
mContext = context;
mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
@@ -107,39 +122,60 @@
mTriangleVertices.put(mTriangleVerticesData).position(0);
}
+
+ public void toggleDepthTest() {
+ mDepthTestEnabled = !mDepthTestEnabled;
+ Log.v(TAG, "mDepthTestEnabled is " + mDepthTestEnabled);
+ }
+
public void onDrawFrame(GL10 glUnused) {
- // Ignore the passed-in GL10 interface, and use the GLES20
- // class's static methods instead.
- GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
- GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
- GLES20.glUseProgram(mProgram);
- checkGlError("glUseProgram");
+ for (int j = 0 ; j < FRAME_REPEAT_TIMES; j ++) {
+ // Ignore the passed-in GL10 interface, and use the GLES20
+ // class's static methods instead.
+ GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+ if (mDepthTestEnabled) {
+ GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+ } else {
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+ GLES20.glUseProgram(mProgram);
+ if (mDepthTestEnabled) {
+ GLES20.glEnable(GLES20.GL_DEPTH_TEST);
+ } else {
+ GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+ }
+ checkGlError("glUseProgram");
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
- mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
- GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
- TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
- checkGlError("glVertexAttribPointer maPosition");
- mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
- GLES20.glEnableVertexAttribArray(maPositionHandle);
- checkGlError("glEnableVertexAttribArray maPositionHandle");
- GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
- TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
- checkGlError("glVertexAttribPointer maTextureHandle");
- GLES20.glEnableVertexAttribArray(maTextureHandle);
- checkGlError("glEnableVertexAttribArray maTextureHandle");
+ mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+ GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ checkGlError("glVertexAttribPointer maPosition");
+ mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+ GLES20.glEnableVertexAttribArray(maPositionHandle);
+ checkGlError("glEnableVertexAttribArray maPositionHandle");
+ GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ checkGlError("glVertexAttribPointer maTextureHandle");
+ GLES20.glEnableVertexAttribArray(maTextureHandle);
+ checkGlError("glEnableVertexAttribArray maTextureHandle");
- long time = SystemClock.uptimeMillis() % 4000L;
- float angle = 0.090f * ((int) time);
- Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);
- Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
- Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
+ for (int i = 0 ; i < REPEAT_RECTANGLES; i ++) {
+ float step = ((float)i) / REPEAT_RECTANGLES;
+ Matrix.setIdentityM(mMMatrix, 0);
+ Matrix.translateM(mMMatrix, 0, 0, step, step / 2);
+ Matrix.scaleM(mMMatrix, 0, 2.0f, 1.0f, 1.0f);
+ Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
+ Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
- GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
- GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
- checkGlError("glDrawArrays");
+ GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+ GLES20.glUniform4f(muOverlayHandle, step , step, step , step);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+ checkGlError("glDrawArrays");
+ }
+ }
}
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
@@ -174,6 +210,12 @@
throw new RuntimeException("Could not get attrib location for uMVPMatrix");
}
+ muOverlayHandle = GLES20.glGetUniformLocation(mProgram, "uOverlay");
+ checkGlError("glGetUniformLocation uOverlay");
+ if (muOverlayHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for muOverlayHandle");
+ }
+
/*
* Create our texture. This has to be done each time the surface is
* created.
@@ -213,6 +255,10 @@
bitmap.recycle();
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+
+ EGLDisplay display = EGL14.eglGetCurrentDisplay();
+ EGL14.eglSwapInterval(display, 0);
+
}
private int loadShader(int shaderType, String source) {
@@ -276,9 +322,10 @@
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
- -1.0f, -0.5f, 0, -0.5f, 0.0f,
- 1.0f, -0.5f, 0, 1.5f, -0.0f,
- 0.0f, 1.11803399f, 0, 0.5f, 1.61803399f };
+ -1.0f, -1.0f, 0, 0.0f, 0.0f,
+ -1.0f, 1.0f, 0, 0.0f, 1.0f,
+ 1.0f, -1.0f, 0, 1.0f, 0.0f,
+ 1.0f, 1.0f, 0, 1.0f, 1.0f, };
private FloatBuffer mTriangleVertices;
@@ -296,8 +343,9 @@
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
+ "uniform vec4 uOverlay;\n" +
"void main() {\n" +
- " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+ " gl_FragColor = texture2D(sTexture, vTextureCoord) * uOverlay;\n" +
"}\n";
private float[] mMVPMatrix = new float[16];
@@ -310,6 +358,7 @@
private int muMVPMatrixHandle;
private int maPositionHandle;
private int maTextureHandle;
+ private int muOverlayHandle;
private Context mContext;
private static final String TAG = "GLES20TriangleRenderer";
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index 33813d1..88ebd1f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -28,6 +28,8 @@
import com.ibm.icu.lang.UScript;
import com.ibm.icu.lang.UScriptRun;
+import com.ibm.icu.text.Bidi;
+import com.ibm.icu.text.BidiRun;
import android.graphics.Paint_Delegate.FontInfo;
@@ -38,7 +40,7 @@
@SuppressWarnings("deprecation")
public class BidiRenderer {
- /*package*/ static class ScriptRun {
+ private static class ScriptRun {
int start;
int limit;
boolean isRtl;
@@ -66,7 +68,7 @@
* @param paint The Paint to use to get the fonts. Should not be null.
* @param text Unidirectional text. Should not be null.
*/
- /*package*/ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
+ public BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
assert (paint != null);
mGraphics = graphics;
mPaint = paint;
@@ -75,13 +77,45 @@
for (FontInfo fontInfo : paint.getFonts()) {
mFonts.add(fontInfo.mFont);
}
+ mBounds = new RectF();
+ }
+
+ /**
+ *
+ * @param x The x-coordinate of the left edge of where the text should be drawn on the given
+ * graphics.
+ * @param y The y-coordinate at which to draw the text on the given mGraphics.
+ *
+ */
+ public BidiRenderer setRenderLocation(float x, float y) {
+ mBounds = new RectF(x, y, x, y);
+ mBaseline = y;
+ return this;
+ }
+
+ /**
+ * Perform Bidi Analysis on the text and then render it.
+ * <p/>
+ * To skip the analysis and render unidirectional text, see {@link
+ * #renderText(int, int, boolean, float[], int, boolean)}
+ */
+ public RectF renderText(int start, int limit, int bidiFlags, float[] advances,
+ int advancesIndex, boolean draw) {
+ Bidi bidi = new Bidi(mText, start, null, 0, limit - start, getIcuFlags(bidiFlags));
+ for (int i = 0; i < bidi.countRuns(); i++) {
+ BidiRun visualRun = bidi.getVisualRun(i);
+ boolean isRtl = visualRun.getDirection() == Bidi.RTL;
+ renderText(visualRun.getStart(), visualRun.getLimit(), isRtl, advances,
+ advancesIndex, draw);
+ }
+ return mBounds;
}
/**
* Render unidirectional text.
- *
+ * <p/>
* This method can also be used to measure the width of the text without actually drawing it.
- *
+ * <p/>
* @param start index of the first character
* @param limit index of the first character that should not be rendered.
* @param isRtl is the text right-to-left
@@ -90,17 +124,12 @@
* @param advancesIndex index into advances from where the advances need to be filled.
* @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics
* at the given co-ordinates
- * @param x The x-coordinate of the left edge of where the text should be drawn on the given
- * graphics.
- * @param y The y-coordinate at which to draw the text on the given mGraphics.
* @return A rectangle specifying the bounds of the text drawn.
*/
- /* package */ RectF renderText(int start, int limit, boolean isRtl, float[] advances,
- int advancesIndex, boolean draw, float x, float y) {
+ public RectF renderText(int start, int limit, boolean isRtl, float[] advances,
+ int advancesIndex, boolean draw) {
// We break the text into scripts and then select font based on it and then render each of
// the script runs.
- mBounds = new RectF(x, y, x, y);
- mBaseline = y;
for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mFonts)) {
int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
@@ -244,4 +273,22 @@
}
run.font = fonts.get(0);
}
+
+ private static int getIcuFlags(int bidiFlag) {
+ switch (bidiFlag) {
+ case Paint.BIDI_LTR:
+ case Paint.BIDI_FORCE_LTR:
+ return Bidi.DIRECTION_LEFT_TO_RIGHT;
+ case Paint.BIDI_RTL:
+ case Paint.BIDI_FORCE_RTL:
+ return Bidi.DIRECTION_RIGHT_TO_LEFT;
+ case Paint.BIDI_DEFAULT_LTR:
+ return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+ case Paint.BIDI_DEFAULT_RTL:
+ return Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT;
+ default:
+ assert false;
+ return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+ }
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 7016136..bd88ae2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -315,7 +315,7 @@
@LayoutlibDelegate
/*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
- int config, int allocSize) {
+ int config, int allocSize, boolean isPremultiplied) {
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"Bitmap.reconfigure() is not supported", null /*data*/);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 2ee06fc..7c8ef70 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -55,16 +55,19 @@
private static final DelegateManager<Canvas_Delegate> sManager =
new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
+
// ---- delegate helper data ----
private final static boolean[] sBoolOut = new boolean[1];
+
// ---- delegate data ----
private Bitmap_Delegate mBitmap;
private GcSnapshot mSnapshot;
private DrawFilter_Delegate mDrawFilter = null;
+
// ---- Public Helper methods ----
/**
@@ -100,206 +103,6 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static boolean isOpaque(Canvas thisCanvas) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return false;
- }
-
- return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
- }
-
- @LayoutlibDelegate
- /*package*/ static int getWidth(Canvas thisCanvas) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return 0;
- }
-
- return canvasDelegate.mBitmap.getImage().getWidth();
- }
-
- @LayoutlibDelegate
- /*package*/ static int getHeight(Canvas thisCanvas) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return 0;
- }
-
- return canvasDelegate.mBitmap.getImage().getHeight();
- }
-
- @LayoutlibDelegate
- /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return;
- }
-
- canvasDelegate.getSnapshot().translate(dx, dy);
- }
-
- @LayoutlibDelegate
- /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return;
- }
-
- canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
- }
-
- @LayoutlibDelegate
- /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return;
- }
-
- canvasDelegate.getSnapshot().scale(sx, sy);
- }
-
- @LayoutlibDelegate
- /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return;
- }
-
- // get the current top graphics2D object.
- GcSnapshot g = canvasDelegate.getSnapshot();
-
- // get its current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform for the given skew.
- float[] mtx = Matrix_Delegate.getSkew(kx, ky);
- AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
-
- // combine them so that the given matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics2D as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
- @LayoutlibDelegate
- /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
- return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
- }
-
- @LayoutlibDelegate
- /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
- return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
- (float) rect.right, (float) rect.bottom);
- }
-
- @LayoutlibDelegate
- /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
- float bottom) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return false;
- }
-
- return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
- }
-
- @LayoutlibDelegate
- /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
- int bottom) {
-
- return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
- }
-
- @LayoutlibDelegate
- /*package*/ static int save(Canvas thisCanvas) {
- return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
- }
-
- @LayoutlibDelegate
- /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return 0;
- }
-
- return canvasDelegate.save(saveFlags);
- }
-
- @LayoutlibDelegate
- /*package*/ static void restore(Canvas thisCanvas) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return;
- }
-
- canvasDelegate.restore();
- }
-
- @LayoutlibDelegate
- /*package*/ static int getSaveCount(Canvas thisCanvas) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return 0;
- }
-
- return canvasDelegate.getSnapshot().size();
- }
-
- @LayoutlibDelegate
- /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
- if (canvasDelegate == null) {
- return;
- }
-
- canvasDelegate.restoreTo(saveCount);
- }
-
- @LayoutlibDelegate
- /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
- Paint paint) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Canvas.drawPoint is not supported.", null, null /*data*/);
- }
-
- @LayoutlibDelegate
- /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Canvas.drawPoint is not supported.", null, null /*data*/);
- }
-
- @LayoutlibDelegate
- /*package*/ static void drawLines(Canvas thisCanvas,
- final float[] pts, final int offset, final int count,
- Paint paint) {
- draw(thisCanvas.getNativeCanvasWrapper(), paint.mNativePaint, false /*compositeOnly*/,
- false /*forceSrcMode*/, new GcSnapshot.Drawable() {
- @Override
- public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
- for (int i = 0 ; i < count ; i += 4) {
- graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
- (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
- }
- }
- });
- }
-
- @LayoutlibDelegate
/*package*/ static void freeCaches() {
// nothing to be done here.
}
@@ -328,36 +131,73 @@
}
@LayoutlibDelegate
- /*package*/ static void copyNativeCanvasState(long srcCanvas, long dstCanvas) {
+ /*package*/ static long initCanvas(long nativeCanvas) {
// get the delegate from the native int.
- Canvas_Delegate srcCanvasDelegate = sManager.getDelegate(srcCanvas);
- if (srcCanvasDelegate == null) {
- return;
+ Canvas_Delegate nativeCanvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (nativeCanvasDelegate == null) {
+ return 0;
}
- // get the delegate from the native int.
- Canvas_Delegate dstCanvasDelegate = sManager.getDelegate(dstCanvas);
- if (dstCanvasDelegate == null) {
- return;
- }
+ Canvas_Delegate newDelegate = new Canvas_Delegate();
+
// TODO: actually copy the canvas state.
+ return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
- /*package*/ static int native_saveLayer(long nativeCanvas, RectF bounds,
- long paint, int layerFlags) {
+ /*package*/
+ static void native_setBitmap(long canvas, long bitmap, boolean copyState) {
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (canvasDelegate == null || bitmapDelegate==null) {
+ return;
+ }
+ canvasDelegate.mBitmap = bitmapDelegate;
+ canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isOpaque(long nativeCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getWidth(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
- Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
- if (paintDelegate == null) {
+ return canvasDelegate.mBitmap.getImage().getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getHeight(long nativeCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
return 0;
}
- return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
+ return canvasDelegate.mBitmap.getImage().getHeight();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_save(long nativeCanvas, int saveFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.save(saveFlags);
}
@LayoutlibDelegate
@@ -380,19 +220,6 @@
}
@LayoutlibDelegate
- /*package*/ static int native_saveLayerAlpha(long nativeCanvas,
- RectF bounds, int alpha,
- int layerFlags) {
- // get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
- if (canvasDelegate == null) {
- return 0;
- }
-
- return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
- }
-
- @LayoutlibDelegate
/*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
@@ -405,6 +232,95 @@
return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
}
+ @LayoutlibDelegate
+ /*package*/ static void native_restore(long nativeCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.restore();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.restoreTo(saveCount);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getSaveCount(long nativeCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.getSnapshot().size();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_translate(long nativeCanvas, float dx, float dy) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().translate(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_scale(long nativeCanvas, float sx, float sy) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().scale(sx, sy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rotate(long nativeCanvas, float degrees) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_skew(long nativeCanvas, float kx, float ky) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot g = canvasDelegate.getSnapshot();
+
+ // get its current matrix
+ AffineTransform currentTx = g.getTransform();
+ // get the AffineTransform for the given skew.
+ float[] mtx = Matrix_Delegate.getSkew(kx, ky);
+ AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ g.setTransform(currentTx);
+ }
@LayoutlibDelegate
/*package*/ static void native_concat(long nCanvas, long nMatrix) {
@@ -469,7 +385,6 @@
float left, float top,
float right, float bottom,
int regionOp) {
-
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
if (canvasDelegate == null) {
@@ -568,15 +483,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_quickReject(long nativeCanvas,
- RectF rect) {
- // FIXME properly implement quickReject
- return false;
- }
-
- @LayoutlibDelegate
- /*package*/ static boolean native_quickReject(long nativeCanvas,
- long path) {
+ /*package*/ static boolean native_quickReject(long nativeCanvas, long path) {
// FIXME properly implement quickReject
return false;
}
@@ -645,10 +552,25 @@
}
@LayoutlibDelegate
+ /*package*/ static void native_drawPoint(long nativeCanvas, float x, float y,
+ long nativePaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+ long nativePaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
/*package*/ static void native_drawLine(long nativeCanvas,
final float startX, final float startY, final float stopX, final float stopY,
long paint) {
-
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@Override
@@ -659,8 +581,19 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawRect(long nativeCanvas, RectF rect, long paint) {
- native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
+ /*package*/ static void native_drawLines(long nativeCanvas,
+ final float[] pts, final int offset, final int count,
+ long nativePaint) {
+ draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
+ false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+ @Override
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ for (int i = 0; i < count; i += 4) {
+ graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1],
+ (int) pts[i + offset + 2], (int) pts[i + offset + 3]);
+ }
+ }
+ });
}
@LayoutlibDelegate
@@ -690,8 +623,9 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawOval(long nativeCanvas, final RectF oval, long paint) {
- if (oval.right > oval.left && oval.bottom > oval.top) {
+ /*package*/ static void native_drawOval(long nativeCanvas, final float left,
+ final float top, final float right, final float bottom, long paint) {
+ if (right > left && bottom > top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@Override
@@ -701,14 +635,14 @@
// draw
if (style == Paint.Style.FILL.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.fillOval((int)oval.left, (int)oval.top,
- (int)oval.width(), (int)oval.height());
+ graphics.fillOval((int)left, (int)top,
+ (int)(right - left), (int)(bottom - top));
}
if (style == Paint.Style.STROKE.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.drawOval((int)oval.left, (int)oval.top,
- (int)oval.width(), (int)oval.height());
+ graphics.drawOval((int)left, (int)top,
+ (int)(right - left), (int)(bottom - top));
}
}
});
@@ -719,15 +653,16 @@
/*package*/ static void native_drawCircle(long nativeCanvas,
float cx, float cy, float radius, long paint) {
native_drawOval(nativeCanvas,
- new RectF(cx - radius, cy - radius, cx + radius, cy + radius),
+ cx - radius, cy - radius, cx + radius, cy + radius,
paint);
}
@LayoutlibDelegate
/*package*/ static void native_drawArc(long nativeCanvas,
- final RectF oval, final float startAngle, final float sweep,
+ final float left, final float top, final float right, final float bottom,
+ final float startAngle, final float sweep,
final boolean useCenter, long paint) {
- if (oval.right > oval.left && oval.bottom > oval.top) {
+ if (right > left && bottom > top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@Override
@@ -735,7 +670,7 @@
int style = paintDelegate.getStyle();
Arc2D.Float arc = new Arc2D.Float(
- oval.left, oval.top, oval.width(), oval.height(),
+ left, top, right - left, bottom - top,
-startAngle, -sweep,
useCenter ? Arc2D.PIE : Arc2D.OPEN);
@@ -758,7 +693,6 @@
/*package*/ static void native_drawRoundRect(long nativeCanvas,
final float left, final float top, final float right, final float bottom,
final float rx, final float ry, long paint) {
-
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@Override
@@ -890,7 +824,6 @@
final float y, int width, int height,
boolean hasAlpha,
long nativePaintOrZero) {
-
// create a temp BufferedImage containing the content.
final BufferedImage image = new BufferedImage(width, height,
hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
@@ -973,41 +906,10 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawText(long nativeCanvas,
- final char[] text, final int index, final int count,
- final float startX, final float startY, final int flags, long paint,
- final long typeface) {
-
- draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
- new GcSnapshot.Drawable() {
- @Override
- public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
- // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
- // Any change to this method should be reflected in Paint.measureText
-
- // assert that the typeface passed is actually the one stored in paint.
- assert (typeface == paintDelegate.mNativeTypeface);
-
-
- // Paint.TextAlign indicates how the text is positioned relative to X.
- // LEFT is the default and there's nothing to do.
- float x = startX;
- int limit = index + count;
- boolean isRtl = flags == Canvas.DIRECTION_RTL;
- if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
- RectF bounds = paintDelegate.measureText(text, index, count, isRtl);
- float m = bounds.right - bounds.left;
- if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
- x -= m / 2;
- } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
- x -= m;
- }
- }
-
- new BidiRenderer(graphics, paintDelegate, text).renderText(
- index, limit, isRtl, null, 0, true, x, startY);
- }
- });
+ /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+ float startX, float startY, int flags, long paint, long typeface) {
+ drawText(nativeCanvas, text, index, count, startX, startY, flags == Canvas.DIRECTION_RTL,
+ paint, typeface);
}
@LayoutlibDelegate
@@ -1024,38 +926,19 @@
@LayoutlibDelegate
/*package*/ static void native_drawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
- float x, float y, int flags, long paint, long typeface) {
+ float x, float y, boolean isRtl, long paint, long typeface) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
+ drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface);
}
@LayoutlibDelegate
/*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
- float x, float y, int flags, long paint, long typeface) {
- native_drawText(nativeCanvas, text, start, count, x, y, flags, paint, typeface);
- }
-
- @LayoutlibDelegate
- /*package*/ static void native_drawPosText(long nativeCanvas,
- char[] text, int index,
- int count, float[] pos,
- long paint) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Canvas.drawPosText is not supported.", null, null /*data*/);
- }
-
- @LayoutlibDelegate
- /*package*/ static void native_drawPosText(long nativeCanvas,
- String text, float[] pos,
- long paint) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Canvas.drawPosText is not supported.", null, null /*data*/);
+ float x, float y, boolean isRtl, long paint, long typeface) {
+ drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
}
@LayoutlibDelegate
@@ -1064,7 +947,7 @@
int count, long path,
float hOffset,
float vOffset, int bidiFlags,
- long paint) {
+ long paint, long typeface) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Canvas.drawTextOnPath is not supported.", null, null /*data*/);
@@ -1075,7 +958,8 @@
String text, long path,
float hOffset,
float vOffset,
- int flags, long paint) {
+ int bidiFlags, long paint,
+ long typeface) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Canvas.drawTextOnPath is not supported.", null, null /*data*/);
@@ -1095,6 +979,7 @@
sManager.removeJavaReferenceFor(nativeCanvas);
}
+
// ---- Private delegate/helper methods ----
/**
@@ -1132,6 +1017,41 @@
canvasDelegate.mSnapshot.draw(drawable);
}
+ private static void drawText(long nativeCanvas, final char[] text, final int index,
+ final int count, final float startX, final float startY, final boolean isRtl,
+ long paint, final long typeface) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ @Override
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
+ // Any change to this method should be reflected in Paint.measureText
+
+ // assert that the typeface passed is actually the one stored in paint.
+ assert (typeface == paintDelegate.mNativeTypeface);
+
+ // Paint.TextAlign indicates how the text is positioned relative to X.
+ // LEFT is the default and there's nothing to do.
+ float x = startX;
+ int limit = index + count;
+ if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+ RectF bounds = paintDelegate.measureText(text, index, count, null, 0,
+ isRtl);
+ float m = bounds.right - bounds.left;
+ if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+ x -= m / 2;
+ } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+ x -= m;
+ }
+ }
+
+ new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, startY)
+ .renderText(index, limit, isRtl, null, 0, true);
+ }
+ });
+ }
+
private Canvas_Delegate(Bitmap_Delegate bitmap) {
mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 5adf4ca..24ef189 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -602,7 +602,7 @@
return 0;
}
- RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags));
+ RectF bounds = delegate.measureText(text, index, count, null, 0, bidiFlags);
return bounds.right - bounds.left;
}
@@ -618,11 +618,11 @@
}
@LayoutlibDelegate
- /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
- float maxWidth, int bidiFlags, float[] measuredWidth) {
+ /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, char[] text,
+ int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -641,7 +641,7 @@
}
// measure from start to end
- RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+ RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags);
float res = bounds.right - bounds.left;
if (measuredWidth != null) {
@@ -660,10 +660,11 @@
}
@LayoutlibDelegate
- /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
+ /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, String text,
+ boolean measureForwards,
float maxWidth, int bidiFlags, float[] measuredWidth) {
- return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
- bidiFlags, measuredWidth);
+ return native_breakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(),
+ maxWidth, bidiFlags, measuredWidth);
}
@LayoutlibDelegate
@@ -950,8 +951,25 @@
@LayoutlibDelegate
/*package*/ static int native_getTextWidths(long native_object, long native_typeface,
char[] text, int index, int count, int bidiFlags, float[] widths) {
- return (int) native_getTextRunAdvances(native_object, native_typeface, text, index, count,
- index, count, bidiFlags, widths, 0);
+
+ if (widths != null) {
+ for (int i = 0; i< count; i++) {
+ widths[i]=0;
+ }
+ }
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ // native_typeface is passed here since Framework's old implementation did not have the
+ // typeface object associated with the Paint. Since, we follow the new framework way,
+ // we store the typeface with the paint and use it directly.
+ assert (native_typeface == delegate.mNativeTypeface);
+
+ RectF bounds = delegate.measureText(text, index, count, widths, 0, bidiFlags);
+ return ((int) (bounds.right - bounds.left));
}
@LayoutlibDelegate
@@ -971,7 +989,7 @@
@LayoutlibDelegate
/*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex) {
+ boolean isRtl, float[] advances, int advancesIndex) {
if (advances != null)
for (int i = advancesIndex; i< advancesIndex+count; i++)
@@ -987,25 +1005,21 @@
// we store the typeface with the paint and use it directly.
assert (native_typeface == delegate.mNativeTypeface);
- boolean isRtl = isRtl(flags);
-
- int limit = index + count;
- RectF bounds = new BidiRenderer(null, delegate, text).renderText(
- index, limit, isRtl, advances, advancesIndex, false, 0, 0);
+ RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, isRtl);
return bounds.right - bounds.left;
}
@LayoutlibDelegate
/*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex) {
+ boolean isRtl, float[] advances, int advancesIndex) {
// FIXME: support contextStart and contextEnd
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count,
- contextStart, contextEnd - contextStart, flags, advances, advancesIndex);
+ contextStart, contextEnd - contextStart, isRtl, advances, advancesIndex);
}
@LayoutlibDelegate
@@ -1062,7 +1076,7 @@
// assert that the typeface passed is actually the one that we had stored.
assert (native_typeface == delegate.mNativeTypeface);
- delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds);
+ delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds);
}
@LayoutlibDelegate
@@ -1158,9 +1172,16 @@
}
}
- /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) {
- return new BidiRenderer(null, this, text).renderText(
- index, index + count, isRtl, null, 0, false, 0, 0);
+ /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
+ int advancesIndex, int bidiFlags) {
+ return new BidiRenderer(null, this, text)
+ .renderText(index, index + count, bidiFlags, advances, advancesIndex, false);
+ }
+
+ /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
+ int advancesIndex, boolean isRtl) {
+ return new BidiRenderer(null, this, text)
+ .renderText(index, index + count, isRtl, advances, advancesIndex, false);
}
private float getFontMetrics(FontMetrics metrics) {
@@ -1198,15 +1219,4 @@
delegate.mFlags &= ~flagMask;
}
}
-
- private static boolean isRtl(int flag) {
- switch(flag) {
- case Paint.BIDI_RTL:
- case Paint.BIDI_FORCE_RTL:
- case Paint.BIDI_DEFAULT_RTL:
- return true;
- default:
- return false;
- }
- }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 0ec7115..7153a90 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -297,14 +297,15 @@
}
@LayoutlibDelegate
- /*package*/ static void native_arcTo(long nPath, RectF oval,
+ /*package*/ static void native_arcTo(long nPath, float left, float top, float right,
+ float bottom,
float startAngle, float sweepAngle, boolean forceMoveTo) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
- pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
+ pathDelegate.arcTo(left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
}
@LayoutlibDelegate
@@ -353,8 +354,8 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addArc(long nPath, RectF oval,
- float startAngle, float sweepAngle) {
+ /*package*/ static void native_addArc(long nPath, float left, float top, float right,
+ float bottom, float startAngle, float sweepAngle) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -362,13 +363,13 @@
// because x/y is the center of the circle, need to offset this by the radius
pathDelegate.mPath.append(new Arc2D.Float(
- oval.left, oval.top, oval.width(), oval.height(),
+ left, top, right - left, bottom - top,
-startAngle, -sweepAngle, Arc2D.OPEN), false);
}
@LayoutlibDelegate
- /*package*/ static void native_addRoundRect(
- long nPath, RectF rect, float rx, float ry, int dir) {
+ /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+ float bottom, float rx, float ry, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -376,14 +377,15 @@
}
pathDelegate.mPath.append(new RoundRectangle2D.Float(
- rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
+ left, top, right - left, bottom - top, rx * 2, ry * 2), false);
}
@LayoutlibDelegate
- /*package*/ static void native_addRoundRect(long nPath, RectF rect, float[] radii, int dir) {
+ /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+ float bottom, float[] radii, int dir) {
// Java2D doesn't support different rounded corners in each corner, so just use the
// first value.
- native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+ native_addRoundRect(nPath, left, top, right, bottom, radii[0], radii[1], dir);
// there can be a case where this API is used but with similar values for all corners, so
// in that case we don't warn.
@@ -710,14 +712,19 @@
* start of the arc. However, if the path is empty, then we call moveTo()
* with the first point of the arc. The sweep angle is tread mod 360.
*
- * @param oval The bounds of oval defining shape and size of the arc
+ * @param left The left of oval defining shape and size of the arc
+ * @param top The top of oval defining shape and size of the arc
+ * @param right The right of oval defining shape and size of the arc
+ * @param bottom The bottom of oval defining shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
* @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
* mod 360.
* @param forceMoveTo If true, always begin a new contour with the arc
*/
- private void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) {
- Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), -startAngle,
+ private void arcTo(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle,
+ boolean forceMoveTo) {
+ Arc2D arc = new Arc2D.Float(left, top, right - left, bottom - top, -startAngle,
-sweepAngle, Arc2D.OPEN);
mPath.append(arc, true /*connect*/);
diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
index 973fa0e..6247dae 100644
--- a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
@@ -37,14 +37,17 @@
switch (dir) {
case 0: // Layout.DIR_REQUEST_LTR
- case 1: // Layout.DIR_REQUEST_RTL
- break; // No change.
- case -1:
- dir = Bidi.LEVEL_DEFAULT_LTR;
+ dir = Bidi.LTR;
break;
- case -2:
+ case 1: // Layout.DIR_REQUEST_RTL
+ dir = Bidi.RTL;
+ break;
+ case -1: // Layout.DIR_REQUEST_DEFAULT_RTL
dir = Bidi.LEVEL_DEFAULT_RTL;
break;
+ case -2: // Layout.DIR_REQUEST_DEFAULT_LTR
+ dir = Bidi.LEVEL_DEFAULT_LTR;
+ break;
default:
// Invalid code. Log error, assume LEVEL_DEFAULT_LTR and continue.
Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Invalid direction flag", null);
diff --git a/tools/layoutlib/bridge/src/dalvik/system/VMRuntime_Delegate.java b/tools/layoutlib/bridge/src/dalvik/system/VMRuntime_Delegate.java
new file mode 100644
index 0000000..36efc3a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/dalvik/system/VMRuntime_Delegate.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide implementation of a select few native methods of {@link VMRuntime}
+ * <p/>
+ * Through the layoutlib_create tool, the original native methods of VMRuntime have been replaced
+ * by calls to methods of the same name in this delegate class.
+ */
+public class VMRuntime_Delegate {
+
+ // Copied from libcore/libdvm/src/main/java/dalvik/system/VMRuntime
+ @LayoutlibDelegate
+ /*package*/ static Object newUnpaddedArray(VMRuntime runtime, Class<?> componentType,
+ int minLength) {
+ // Dalvik has 32bit pointers, the array header is 16bytes plus 4bytes for dlmalloc,
+ // allocations are 8byte aligned so having 4bytes of array data avoids padding.
+ if (!componentType.isPrimitive()) {
+ int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+ return java.lang.reflect.Array.newInstance(componentType, size);
+ } else if (componentType == char.class) {
+ int bytes = 20 + (2 * minLength);
+ int alignedUpBytes = (bytes + 7) & -8;
+ int dataBytes = alignedUpBytes - 20;
+ int size = dataBytes / 2;
+ return new char[size];
+ } else if (componentType == int.class) {
+ int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+ return new int[size];
+ } else if (componentType == byte.class) {
+ int bytes = 20 + minLength;
+ int alignedUpBytes = (bytes + 7) & -8;
+ int dataBytes = alignedUpBytes - 20;
+ int size = dataBytes;
+ return new byte[size];
+ } else if (componentType == boolean.class) {
+ int bytes = 20 + minLength;
+ int alignedUpBytes = (bytes + 7) & -8;
+ int dataBytes = alignedUpBytes - 20;
+ int size = dataBytes;
+ return new boolean[size];
+ } else if (componentType == short.class) {
+ int bytes = 20 + (2 * minLength);
+ int alignedUpBytes = (bytes + 7) & -8;
+ int dataBytes = alignedUpBytes - 20;
+ int size = dataBytes / 2;
+ return new short[size];
+ } else if (componentType == float.class) {
+ int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+ return new float[size];
+ } else if (componentType == long.class) {
+ return new long[minLength];
+ } else if (componentType == double.class) {
+ return new double[minLength];
+ } else {
+ assert componentType == void.class;
+ throw new IllegalArgumentException("Can't allocate an array of void");
+ }
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 19d249b..71947b0 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -148,12 +148,12 @@
}
@LayoutlibDelegate
- /*package*/ static String getISO3CountryNative(String locale) {
+ /*package*/ static String getISO3Country(String locale) {
return "";
}
@LayoutlibDelegate
- /*package*/ static String getISO3LanguageNative(String locale) {
+ /*package*/ static String getISO3Language(String locale) {
return "";
}
@@ -184,11 +184,6 @@
}
@LayoutlibDelegate
- /*package*/ static String languageTagForLocale(String locale) {
- return "";
- }
-
- @LayoutlibDelegate
/*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) {
// Used by Calendar.
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
index 274516c..8b362ec 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -41,27 +41,29 @@
*/
public class TestDelegates extends TestCase {
+ private List<String> mErrors = new ArrayList<String>();
+
public void testNativeDelegates() {
final String[] classes = CreateInfo.DELEGATE_CLASS_NATIVES;
- final int count = classes.length;
- for (int i = 0 ; i < count ; i++) {
- loadAndCompareClasses(classes[i], classes[i] + "_Delegate");
+ mErrors.clear();
+ for (String clazz : classes) {
+ loadAndCompareClasses(clazz, clazz + "_Delegate");
}
+ assertTrue(getErrors(), mErrors.isEmpty());
}
public void testMethodDelegates() {
final String[] methods = CreateInfo.DELEGATE_METHODS;
- final int count = methods.length;
- for (int i = 0 ; i < count ; i++) {
- String methodName = methods[i];
-
+ mErrors.clear();
+ for (String methodName : methods) {
// extract the class name
String className = methodName.substring(0, methodName.indexOf('#'));
String targetClassName = className.replace('$', '_') + "_Delegate";
loadAndCompareClasses(className, targetClassName);
}
+ assertTrue(getErrors(), mErrors.isEmpty());
}
private void loadAndCompareClasses(String originalClassName, String delegateClassName) {
@@ -73,9 +75,9 @@
compare(originalClass, delegateClass);
} catch (ClassNotFoundException e) {
- fail("Failed to load class: " + e.getMessage());
+ mErrors.add("Failed to load class: " + e.getMessage());
} catch (SecurityException e) {
- fail("Failed to load class: " + e.getMessage());
+ mErrors.add("Failed to load class: " + e.getMessage());
}
}
@@ -122,35 +124,39 @@
parameters);
// check the return type of the methods match.
- assertTrue(
- String.format("Delegate method %1$s.%2$s does not match the corresponding " +
- "framework method which returns %3$s",
- delegateClass.getName(),
- getMethodName(delegateMethod),
- originalMethod.getReturnType().getName()),
- delegateMethod.getReturnType() == originalMethod.getReturnType());
+ if (delegateMethod.getReturnType() != originalMethod.getReturnType()) {
+ mErrors.add(
+ String.format("Delegate method %1$s.%2$s does not match the " +
+ "corresponding framework method which returns %3$s",
+ delegateClass.getName(),
+ getMethodName(delegateMethod),
+ originalMethod.getReturnType().getName()));
+ }
// check that the method has the annotation
- assertNotNull(
- String.format(
- "Delegate method %1$s for class %2$s does not have the @LayoutlibDelegate annotation",
- delegateMethod.getName(),
- originalClass.getName()),
- delegateMethod.getAnnotation(LayoutlibDelegate.class));
+ if (delegateMethod.getAnnotation(LayoutlibDelegate.class) == null) {
+ mErrors.add(
+ String.format("Delegate method %1$s for class %2$s does not have the " +
+ "@LayoutlibDelegate annotation",
+ delegateMethod.getName(),
+ originalClass.getName()));
+ }
// check that the method is static
- assertTrue(
- String.format(
- "Delegate method %1$s for class %2$s is not static",
- delegateMethod.getName(),
- originalClass.getName()),
- (delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
+ if ((delegateMethod.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
+ mErrors.add(
+ String.format(
+ "Delegate method %1$s for class %2$s is not static",
+ delegateMethod.getName(),
+ originalClass.getName())
+ );
+ }
// add the method as checked.
checkedDelegateMethods.add(delegateMethod);
} catch (NoSuchMethodException e) {
String name = getMethodName(originalMethod, parameters);
- fail(String.format("Missing %1$s.%2$s", delegateClass.getName(), name));
+ mErrors.add(String.format("Missing %1$s.%2$s", delegateClass.getName(), name));
}
}
@@ -167,12 +173,12 @@
continue;
}
- assertTrue(
- String.format(
- "Delegate method %1$s.%2$s is not used anymore and must be removed",
- delegateClass.getName(),
- getMethodName(delegateMethod)),
- checkedDelegateMethods.contains(delegateMethod));
+ if (!checkedDelegateMethods.contains(delegateMethod)) {
+ mErrors.add(String.format(
+ "Delegate method %1$s.%2$s is not used anymore and must be removed",
+ delegateClass.getName(),
+ getMethodName(delegateMethod)));
+ }
}
}
@@ -203,4 +209,12 @@
return sb.toString();
}
+
+ private String getErrors() {
+ StringBuilder s = new StringBuilder();
+ for (String error : mErrors) {
+ s.append(error).append('\n');
+ }
+ return s.toString();
+ }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 1f7a28e..552fb6c 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -152,6 +152,7 @@
"com.android.internal.util.XmlUtils#convertValueToInt",
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
"android.os.SystemProperties#native_get",
+ "dalvik.system.VMRuntime#newUnpaddedArray"
};
/**
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index e7e6767..ddca85e 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -221,12 +221,22 @@
return key;
}
- private Object getListener(int key, boolean force) {
- Log.d(TAG, "getListener() key=" + key + " force=" + force);
+ private Object peekListener(int key) {
+ Log.d(TAG, "peekListener() key=" + key);
if (key == INVALID_LISTENER_KEY)
return null;
synchronized (mListenerMapLock) {
- if (!force) {
+ return mListenerMap.get(key);
+ }
+ }
+
+
+ private Object getListener(int key, boolean forceRemove) {
+ Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
+ if (key == INVALID_LISTENER_KEY)
+ return null;
+ synchronized (mListenerMapLock) {
+ if (!forceRemove) {
int count = mListenerMapCount.get(key);
Log.d(TAG, "count=" + count);
mListenerMapCount.put(key, --count);
@@ -322,7 +332,7 @@
break;
case START_OSU_BROWSER:
- listener = getListener(message.arg2, true);
+ listener = peekListener(message.arg2);
if (listener != null) {
ParcelableString str = (ParcelableString) message.obj;
if (str == null || str.string == null)