Merge "Use an integer for the channel id."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c1799a1..d0aa368c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -109,6 +109,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index 804a524..a8bdaea 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5118,6 +5118,7 @@
field public static final java.lang.String USB_SERVICE = "usb";
field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
+ field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
field public static final java.lang.String WIFI_SERVICE = "wifi";
field public static final java.lang.String WINDOW_SERVICE = "window";
}
@@ -10868,19 +10869,9 @@
method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
}
- public class Metadata {
- method public boolean getBoolean(int);
- method public boolean has(int);
- method public java.util.Set<java.lang.Integer> keySet();
- field public static final int PAUSE_AVAILABLE = 1; // 0x1
- field public static final int SEEK_AVAILABLE = 4; // 0x4
- field public static final int SEEK_BACKWARD_AVAILABLE = 2; // 0x2
- field public static final int SEEK_FORWARD_AVAILABLE = 3; // 0x3
- }
-
public class RemoteControlClient {
- ctor public RemoteControlClient(android.content.ComponentName);
- ctor public RemoteControlClient(android.content.ComponentName, android.os.Looper);
+ ctor public RemoteControlClient(android.app.PendingIntent);
+ ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
method public void setPlaybackState(int);
method public void setTransportControlFlags(int);
@@ -11774,7 +11765,6 @@
method public static void incrementOperationCount(int);
method public static void incrementOperationCount(int, int);
method public static void setThreadStatsTag(int);
- method public static deprecated void setThreadStatsTag(java.lang.String);
method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
field public static final int UNSUPPORTED = -1; // 0xffffffff
@@ -12444,6 +12434,142 @@
method public void setWorkSource(android.os.WorkSource);
}
+ public class WpsInfo implements android.os.Parcelable {
+ ctor public WpsInfo();
+ ctor public WpsInfo(android.net.wifi.WpsInfo);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int DISPLAY = 1; // 0x1
+ field public static final int INVALID = 4; // 0x4
+ field public static final int KEYPAD = 2; // 0x2
+ field public static final int LABEL = 3; // 0x3
+ field public static final int PBC = 0; // 0x0
+ field public java.lang.String pin;
+ field public int setup;
+ }
+
+}
+
+package android.net.wifi.p2p {
+
+ public class WifiP2pConfig implements android.os.Parcelable {
+ ctor public WifiP2pConfig();
+ ctor public WifiP2pConfig(android.net.wifi.p2p.WifiP2pConfig);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public java.lang.String deviceAddress;
+ field public int groupOwnerIntent;
+ field public android.net.wifi.WpsInfo wps;
+ }
+
+ public class WifiP2pDevice implements android.os.Parcelable {
+ ctor public WifiP2pDevice();
+ ctor public WifiP2pDevice(android.net.wifi.p2p.WifiP2pDevice);
+ method public int describeContents();
+ method public boolean isGroupOwner();
+ method public boolean isServiceDiscoveryCapable();
+ method public boolean wpsDisplaySupported();
+ method public boolean wpsKeypadSupported();
+ method public boolean wpsPbcSupported();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int AVAILABLE = 3; // 0x3
+ field public static final int CONNECTED = 0; // 0x0
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int FAILED = 2; // 0x2
+ field public static final int INVITED = 1; // 0x1
+ field public static final int UNAVAILABLE = 4; // 0x4
+ field public java.lang.String deviceAddress;
+ field public java.lang.String deviceName;
+ field public java.lang.String primaryDeviceType;
+ field public java.lang.String secondaryDeviceType;
+ field public int status;
+ }
+
+ public class WifiP2pDeviceList implements android.os.Parcelable {
+ ctor public WifiP2pDeviceList();
+ ctor public WifiP2pDeviceList(android.net.wifi.p2p.WifiP2pDeviceList);
+ method public int describeContents();
+ method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getDeviceList();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public class WifiP2pGroup implements android.os.Parcelable {
+ ctor public WifiP2pGroup();
+ ctor public WifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup);
+ method public int describeContents();
+ method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getClientList();
+ method public java.lang.String getInterface();
+ method public java.lang.String getNetworkName();
+ method public android.net.wifi.p2p.WifiP2pDevice getOwner();
+ method public java.lang.String getPassphrase();
+ method public boolean isGroupOwner();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public class WifiP2pInfo implements android.os.Parcelable {
+ ctor public WifiP2pInfo();
+ ctor public WifiP2pInfo(android.net.wifi.p2p.WifiP2pInfo);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public boolean groupFormed;
+ field public java.net.InetAddress groupOwnerAddress;
+ field public boolean isGroupOwner;
+ }
+
+ public class WifiP2pManager {
+ method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
+ method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
+ method public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
+ method public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+ field public static final int BUSY = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final java.lang.String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
+ field public static final java.lang.String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
+ field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_p2p_state";
+ field public static final int P2P_UNSUPPORTED = 1; // 0x1
+ field public static final java.lang.String WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
+ field public static final java.lang.String WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED";
+ field public static final java.lang.String WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED";
+ field public static final int WIFI_P2P_STATE_DISABLED = 1; // 0x1
+ field public static final int WIFI_P2P_STATE_ENABLED = 2; // 0x2
+ field public static final java.lang.String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
+ }
+
+ public static abstract interface WifiP2pManager.ActionListener {
+ method public abstract void onFailure(int);
+ method public abstract void onSuccess();
+ }
+
+ public static class WifiP2pManager.Channel {
+ }
+
+ public static abstract interface WifiP2pManager.ChannelListener {
+ method public abstract void onChannelDisconnected();
+ }
+
+ public static abstract interface WifiP2pManager.ConnectionInfoListener {
+ method public abstract void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
+ }
+
+ public static abstract interface WifiP2pManager.GroupInfoListener {
+ method public abstract void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
+ }
+
+ public static abstract interface WifiP2pManager.PeerListListener {
+ method public abstract void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
+ }
+
}
package android.nfc {
@@ -23017,6 +23143,7 @@
method public void scrollTo(int, int);
method public void sendAccessibilityEvent(int);
method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
+ method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
method public void setActivated(boolean);
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
@@ -23193,6 +23320,17 @@
field public static android.util.Property Y;
}
+ public static class View.AccessibilityDelegate {
+ ctor public View.AccessibilityDelegate();
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
public static class View.BaseSavedState extends android.view.AbsSavedState {
ctor public View.BaseSavedState(android.os.Parcel);
ctor public View.BaseSavedState(android.os.Parcelable);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 029d107..dbf4de8 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -189,6 +189,7 @@
public static final String KEY_ERROR_CODE = "errorCode";
public static final String KEY_ERROR_MESSAGE = "errorMessage";
public static final String KEY_USERDATA = "userdata";
+
/**
* Authenticators using 'customTokens' option will also get the UID of the
* caller
@@ -814,11 +815,16 @@
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ final Bundle optionsIn = new Bundle();
+ if (options != null) {
+ optionsIn.putAll(options);
+ }
+ optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
mService.getAuthToken(mResponse, account, authTokenType,
false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
- options);
+ optionsIn);
}
}.start();
}
@@ -895,16 +901,11 @@
*/
@Deprecated
public AccountManagerFuture<Bundle> getAuthToken(
- final Account account, final String authTokenType, final boolean notifyAuthFailure,
+ final Account account, final String authTokenType,
+ final boolean notifyAuthFailure,
AccountManagerCallback<Bundle> callback, Handler handler) {
- if (account == null) throw new IllegalArgumentException("account is null");
- if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- return new AmsTask(null, handler, callback) {
- public void doWork() throws RemoteException {
- mService.getAuthToken(mResponse, account, authTokenType,
- notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
- }
- }.start();
+ return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback,
+ handler);
}
/**
@@ -978,15 +979,21 @@
* account before requesting an auth token.
*/
public AccountManagerFuture<Bundle> getAuthToken(
- final Account account, final String authTokenType,
- final Bundle options, final boolean notifyAuthFailure,
+ final Account account, final String authTokenType, final Bundle options,
+ final boolean notifyAuthFailure,
AccountManagerCallback<Bundle> callback, Handler handler) {
+
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ final Bundle optionsIn = new Bundle();
+ if (options != null) {
+ optionsIn.putAll(options);
+ }
+ optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(null, handler, callback) {
public void doWork() throws RemoteException {
mService.getAuthToken(mResponse, account, authTokenType,
- notifyAuthFailure, false /* expectActivityLaunch */, options);
+ notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
}
}.start();
}
@@ -1044,10 +1051,16 @@
final Bundle addAccountOptions,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ final Bundle optionsIn = new Bundle();
+ if (addAccountOptions != null) {
+ optionsIn.putAll(addAccountOptions);
+ }
+ optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
mService.addAcount(mResponse, accountType, authTokenType,
- requiredFeatures, activity != null, addAccountOptions);
+ requiredFeatures, activity != null, optionsIn);
}
}.start();
}
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 20d5b96..173da8d 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -16,10 +16,6 @@
package android.accounts;
-import com.android.internal.R;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.TelephonyIntents;
-
import android.Manifest;
import android.app.ActivityManager;
import android.app.Notification;
@@ -51,13 +47,13 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
-import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import com.android.internal.R;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -924,9 +920,6 @@
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
- final int callerUid = Binder.getCallingUid();
- final int callerPid = Binder.getCallingPid();
-
AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
mAuthenticatorCache.getServiceInfo(
AuthenticatorDescription.newKey(account.type));
@@ -934,20 +927,19 @@
authenticatorInfo != null && authenticatorInfo.type.customTokens;
// skip the check if customTokens
+ final int callerUid = Binder.getCallingUid();
final boolean permissionGranted = customTokens ||
permissionIsGranted(account, authTokenType, callerUid);
final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
loginOptionsIn;
- if (customTokens) {
- // let authenticator know the identity of the caller
- loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
- loginOptions.putInt(AccountManager.KEY_CALLER_PID, callerPid);
- if (notifyOnAuthFailure) {
- loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
- }
+ // let authenticator know the identity of the caller
+ loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
+ loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
+ if (notifyOnAuthFailure) {
+ loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
}
-
+
long identityToken = clearCallingIdentity();
try {
// if the caller has permission, do the peek. otherwise go the more expensive
@@ -1120,7 +1112,7 @@
public void addAcount(final IAccountManagerResponse response, final String accountType,
final String authTokenType, final String[] requiredFeatures,
- final boolean expectActivityLaunch, final Bundle options) {
+ final boolean expectActivityLaunch, final Bundle optionsIn) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "addAccount: accountType " + accountType
+ ", response " + response
@@ -1133,6 +1125,13 @@
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
checkManageAccountsPermission();
+
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
+ options.putInt(AccountManager.KEY_CALLER_UID, uid);
+ options.putInt(AccountManager.KEY_CALLER_PID, pid);
+
long identityToken = clearCallingIdentity();
try {
new Session(response, accountType, expectActivityLaunch,
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0d4a067..be00aa5 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -915,6 +915,7 @@
com.android.internal.R.styleable.ActionBar_LayoutParams);
gravity = a.getInt(
com.android.internal.R.styleable.ActionBar_LayoutParams_layout_gravity, -1);
+ a.recycle();
}
public LayoutParams(int width, int height) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 4b2a8d2..bd42e34 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -42,6 +42,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.pm.ManifestDigest;
+import android.content.pm.VerifierDeviceIdentity;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -1208,6 +1209,19 @@
// TODO:
}
+ /**
+ * @hide
+ */
+ @Override
+ public VerifierDeviceIdentity getVerifierDeviceIdentity() {
+ try {
+ return mPM.getVerifierDeviceIdentity();
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return null;
+ }
+
private final ContextImpl mContext;
private final IPackageManager mPM;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 48f94d0..9468581 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1647,11 +1647,10 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.net.wifi.p2p.WifiP2pManager} for handling management of
- * Wi-Fi p2p.
+ * Wi-Fi peer-to-peer connections.
*
* @see #getSystemService
* @see android.net.wifi.p2p.WifiP2pManager
- * @hide
*/
public static final String WIFI_P2P_SERVICE = "wifip2p";
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 9678d48..684c4fe 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -191,12 +191,6 @@
private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds
private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours
- /**
- * The amount of time (in milliseconds) to wait after attempting a bind
- * before canceling a sync and disabling the sync adapter
- */
- public static final long BIND_TIMEOUT_MS = 5 * 60 * 1000;
-
public void onAccountsUpdated(Account[] accounts) {
// remember if this was the first time this was called after an update
final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;
@@ -1074,9 +1068,6 @@
pw.print(" - ");
pw.print(activeSyncContext.mSyncOperation.dump(false));
pw.println();
- if (activeSyncContext.mSyncAdapter == null) {
- pw.println(" **** Waiting for onServiceConnected ****");
- }
}
synchronized (mSyncQueue) {
@@ -1433,7 +1424,6 @@
public void handleMessage(Message msg) {
long earliestFuturePollTime = Long.MAX_VALUE;
long nextPendingSyncTime = Long.MAX_VALUE;
- long nextBindTimeoutTime = Long.MAX_VALUE;
// Setting the value here instead of a method because we want the dumpsys logs
// to have the most recent value used.
@@ -1441,7 +1431,6 @@
waitUntilReadyToRun();
mDataConnectionIsConnected = readDataConnectionState();
mSyncManagerWakeLock.acquire();
- nextBindTimeoutTime = auditRunningSyncsForStuckBindsLocked();
// Always do this first so that we be sure that any periodic syncs that
// are ready to run have been converted into pending syncs. This allows the
// logic that considers the next steps to take based on the set of pending syncs
@@ -1543,7 +1532,6 @@
break;
}
} finally {
- nextPendingSyncTime = Math.min(nextBindTimeoutTime, nextPendingSyncTime);
manageSyncNotificationLocked();
manageSyncAlarmLocked(earliestFuturePollTime, nextPendingSyncTime);
mSyncTimeTracker.update();
@@ -1552,36 +1540,6 @@
}
/**
- * Looks to see if any of the active syncs have been waiting for a bind for too long,
- * and if so the sync is canceled and the sync adapter is disabled for that account.
- * @return the earliest time that an active sync can have waited too long to bind,
- * relative to {@link android.os.SystemClock#elapsedRealtime()}.
- */
- private long auditRunningSyncsForStuckBindsLocked() {
- final long now = SystemClock.elapsedRealtime();
- long oldest = Long.MAX_VALUE;
- for (ActiveSyncContext active : mActiveSyncContexts) {
- if (active.mSyncAdapter == null) {
- final long timeoutTime = active.mStartTime + BIND_TIMEOUT_MS;
- if (timeoutTime < now) {
- Log.w(TAG, "canceling long-running bind and disabling sync for "
- + active.mSyncOperation.account + ", authority "
- + active.mSyncOperation.authority);
- runSyncFinishedOrCanceledLocked(null, active);
- ContentResolver.setIsSyncable(active.mSyncOperation.account,
- active.mSyncOperation.authority, 0);
- } else {
- if (oldest > timeoutTime) {
- oldest = timeoutTime;
- }
- }
- }
- }
-
- return oldest;
- }
-
- /**
* Turn any periodic sync operations that are ready to run into pending sync operations.
* @return the desired start time of the earliest future periodic sync operation,
* in milliseconds since boot
@@ -1861,17 +1819,13 @@
synchronized (mSyncQueue){
mSyncQueue.remove(candidate);
}
- ActiveSyncContext newSyncContext = dispatchSyncOperation(candidate);
- if (newSyncContext != null) {
- nextReadyToRunTime = Math.min(nextReadyToRunTime,
- newSyncContext.mStartTime + BIND_TIMEOUT_MS);
- }
+ dispatchSyncOperation(candidate);
}
return nextReadyToRunTime;
}
- private ActiveSyncContext dispatchSyncOperation(SyncOperation op) {
+ private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
Log.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
@@ -1888,7 +1842,7 @@
Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
+ ", removing settings for it");
mSyncStorageEngine.removeAuthority(op.account, op.authority);
- return null;
+ return false;
}
ActiveSyncContext activeSyncContext =
@@ -1901,10 +1855,10 @@
if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) {
Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
closeActiveSyncContext(activeSyncContext);
- return null;
+ return false;
}
- return activeSyncContext;
+ return true;
}
private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,
diff --git a/core/java/android/content/pm/ActivityInfo.aidl b/core/java/android/content/pm/ActivityInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ApplicationInfo.aidl b/core/java/android/content/pm/ApplicationInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/FeatureInfo.aidl b/core/java/android/content/pm/FeatureInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/IPackageDataObserver.aidl b/core/java/android/content/pm/IPackageDataObserver.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 08aef16..5e6e768 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -38,6 +38,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
+import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
import android.content.IntentSender;
@@ -359,4 +360,6 @@
in ManifestDigest manifestDigest);
void verifyPendingInstall(int id, boolean verified, in String message);
+
+ VerifierDeviceIdentity getVerifierDeviceIdentity();
}
diff --git a/core/java/android/content/pm/IPackageStatsObserver.aidl b/core/java/android/content/pm/IPackageStatsObserver.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/InstrumentationInfo.aidl b/core/java/android/content/pm/InstrumentationInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ManifestDigest.aidl b/core/java/android/content/pm/ManifestDigest.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/PackageInfo.aidl b/core/java/android/content/pm/PackageInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/PackageInfoLite.aidl b/core/java/android/content/pm/PackageInfoLite.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b4e3988..dcb6776 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2614,4 +2614,14 @@
public static int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
+
+ /**
+ * Returns the device identity that verifiers can use to associate their
+ * scheme to a particular device. This should not be used by anything other
+ * than a package verifier.
+ *
+ * @return identity that uniquely identifies current device
+ * @hide
+ */
+ public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c61e32f..e7b844c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -92,6 +92,7 @@
private String mArchiveSourcePath;
private String[] mSeparateProcesses;
+ private boolean mOnlyCoreApps;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME)
? null : Build.VERSION.CODENAME;
@@ -180,6 +181,10 @@
mSeparateProcesses = procs;
}
+ public void setOnlyCoreApps(boolean onlyCoreApps) {
+ mOnlyCoreApps = onlyCoreApps;
+ }
+
private static final boolean isPackageFilename(String name) {
return name.endsWith(".apk");
}
@@ -433,18 +438,22 @@
if (pkg == null) {
- if (errorException != null) {
- Slog.w(TAG, mArchiveSourcePath, errorException);
- } else {
- Slog.w(TAG, mArchiveSourcePath + " (at "
- + parser.getPositionDescription()
- + "): " + errorText[0]);
+ // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
+ // just means to skip this app so don't make a fuss about it.
+ if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) {
+ if (errorException != null) {
+ Slog.w(TAG, mArchiveSourcePath, errorException);
+ } else {
+ Slog.w(TAG, mArchiveSourcePath + " (at "
+ + parser.getPositionDescription()
+ + "): " + errorText[0]);
+ }
+ if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ }
}
parser.close();
assmgr.close();
- if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- }
return null;
}
@@ -782,6 +791,14 @@
}
int type;
+ if (mOnlyCoreApps) {
+ boolean core = attrs.getAttributeBooleanValue(null, "coreApp", false);
+ if (!core) {
+ mParseError = PackageManager.INSTALL_SUCCEEDED;
+ return null;
+ }
+ }
+
final Package pkg = new Package(pkgName);
boolean foundApp = false;
diff --git a/core/java/android/content/pm/PackageStats.aidl b/core/java/android/content/pm/PackageStats.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ParceledListSlice.aidl b/core/java/android/content/pm/ParceledListSlice.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/PermissionGroupInfo.aidl b/core/java/android/content/pm/PermissionGroupInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/PermissionInfo.aidl b/core/java/android/content/pm/PermissionInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ProviderInfo.aidl b/core/java/android/content/pm/ProviderInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ResolveInfo.aidl b/core/java/android/content/pm/ResolveInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/ServiceInfo.aidl b/core/java/android/content/pm/ServiceInfo.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/content/pm/Signature.aidl b/core/java/android/content/pm/Signature.aidl
old mode 100755
new mode 100644
diff --git a/wifi/java/android/net/wifi/Wps.aidl b/core/java/android/content/pm/VerifierDeviceIdentity.aidl
similarity index 82%
copy from wifi/java/android/net/wifi/Wps.aidl
copy to core/java/android/content/pm/VerifierDeviceIdentity.aidl
index ba82a9a..eb076ae 100644
--- a/wifi/java/android/net/wifi/Wps.aidl
+++ b/core/java/android/content/pm/VerifierDeviceIdentity.aidl
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2010, The Android Open Source Project
+/*
+ * Copyright 2011, 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.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi;
+package android.content.pm;
-parcelable Wps;
+parcelable VerifierDeviceIdentity;
diff --git a/core/java/android/content/pm/VerifierDeviceIdentity.java b/core/java/android/content/pm/VerifierDeviceIdentity.java
new file mode 100644
index 0000000..bfebe0f
--- /dev/null
+++ b/core/java/android/content/pm/VerifierDeviceIdentity.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011 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.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * An identity that uniquely identifies a particular device. In this
+ * implementation, the identity is represented as a 64-bit integer encoded to a
+ * 13-character string using RFC 4648's Base32 encoding without the trailing
+ * padding. This makes it easy for users to read and write the code without
+ * confusing 'I' (letter) with '1' (one) or 'O' (letter) with '0' (zero).
+ *
+ * @hide
+ */
+public class VerifierDeviceIdentity implements Parcelable {
+ /**
+ * Encoded size of a long (64-bit) into Base32. This format will end up
+ * looking like XXXX-XXXX-XXXX-X (length ignores hyphens) when applied with
+ * the GROUP_SIZE below.
+ */
+ private static final int LONG_SIZE = 13;
+
+ /**
+ * Size of groupings when outputting as strings. This helps people read it
+ * out and keep track of where they are.
+ */
+ private static final int GROUP_SIZE = 4;
+
+ private final long mIdentity;
+
+ private final String mIdentityString;
+
+ /**
+ * Create a verifier device identity from a long.
+ *
+ * @param identity device identity in a 64-bit integer.
+ * @throws
+ */
+ public VerifierDeviceIdentity(long identity) {
+ mIdentity = identity;
+ mIdentityString = encodeBase32(identity);
+ }
+
+ private VerifierDeviceIdentity(Parcel source) {
+ final long identity = source.readLong();
+
+ mIdentity = identity;
+ mIdentityString = encodeBase32(identity);
+ }
+
+ /**
+ * Generate a new device identity.
+ *
+ * @return random uniformly-distributed device identity
+ */
+ public static VerifierDeviceIdentity generate() {
+ final SecureRandom sr = new SecureRandom();
+ return generate(sr);
+ }
+
+ /**
+ * Generate a new device identity using a provided random number generator
+ * class. This is used for testing.
+ *
+ * @param rng random number generator to retrieve the next long from
+ * @return verifier device identity based on the input from the provided
+ * random number generator
+ */
+ static VerifierDeviceIdentity generate(Random rng) {
+ long identity = rng.nextLong();
+ return new VerifierDeviceIdentity(identity);
+ }
+
+ private static final char ENCODE[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', '2', '3', '4', '5', '6', '7',
+ };
+
+ private static final char SEPARATOR = '-';
+
+ private static final String encodeBase32(long input) {
+ final char[] alphabet = ENCODE;
+
+ /*
+ * Make a character array with room for the separators between each
+ * group.
+ */
+ final char encoded[] = new char[LONG_SIZE + (LONG_SIZE / GROUP_SIZE)];
+
+ int index = encoded.length;
+ for (int i = 0; i < LONG_SIZE; i++) {
+ /*
+ * Make sure we don't put a separator at the beginning. Since we're
+ * building from the rear of the array, we use (LONG_SIZE %
+ * GROUP_SIZE) to make the odd-size group appear at the end instead
+ * of the beginning.
+ */
+ if (i > 0 && (i % GROUP_SIZE) == (LONG_SIZE % GROUP_SIZE)) {
+ encoded[--index] = SEPARATOR;
+ }
+
+ /*
+ * Extract 5 bits of data, then shift it out.
+ */
+ final int group = (int) (input & 0x1F);
+ input >>>= 5;
+
+ encoded[--index] = alphabet[group];
+ }
+
+ return String.valueOf(encoded);
+ }
+
+ // TODO move this out to its own class (android.util.Base32)
+ private static final long decodeBase32(byte[] input) throws IllegalArgumentException {
+ long output = 0L;
+ int numParsed = 0;
+
+ final int N = input.length;
+ for (int i = 0; i < N; i++) {
+ final int group = input[i];
+
+ /*
+ * This essentially does the reverse of the ENCODED alphabet above
+ * without a table. A..Z are 0..25 and 2..7 are 26..31.
+ */
+ final int value;
+ if ('A' <= group && group <= 'Z') {
+ value = group - 'A';
+ } else if ('2' <= group && group <= '7') {
+ value = group - ('2' - 26);
+ } else if (group == SEPARATOR) {
+ continue;
+ } else {
+ throw new IllegalArgumentException("base base-32 character: " + group);
+ }
+
+ output = (output << 5) | value;
+ numParsed++;
+
+ if (numParsed == 1) {
+ if ((value & 0xF) != value) {
+ throw new IllegalArgumentException("illegal start character; will overflow");
+ }
+ } else if (numParsed > 13) {
+ throw new IllegalArgumentException("too long; should have 13 characters");
+ }
+ }
+
+ if (numParsed != 13) {
+ throw new IllegalArgumentException("too short; should have 13 characters");
+ }
+
+ return output;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) mIdentity;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof VerifierDeviceIdentity)) {
+ return false;
+ }
+
+ final VerifierDeviceIdentity o = (VerifierDeviceIdentity) other;
+ return mIdentity == o.mIdentity;
+ }
+
+ @Override
+ public String toString() {
+ return mIdentityString;
+ }
+
+ public static VerifierDeviceIdentity parse(String deviceIdentity)
+ throws IllegalArgumentException {
+ final byte[] input;
+ try {
+ input = deviceIdentity.getBytes("US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("bad base-32 characters in input");
+ }
+
+ return new VerifierDeviceIdentity(decodeBase32(input));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mIdentity);
+ }
+
+ public static final Parcelable.Creator<VerifierDeviceIdentity> CREATOR
+ = new Parcelable.Creator<VerifierDeviceIdentity>() {
+ public VerifierDeviceIdentity createFromParcel(Parcel source) {
+ return new VerifierDeviceIdentity(source);
+ }
+
+ public VerifierDeviceIdentity[] newArray(int size) {
+ return new VerifierDeviceIdentity[size];
+ }
+ };
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d7f901a..4f19010 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -72,6 +72,7 @@
static final String TAG = "Resources";
private static final boolean DEBUG_LOAD = false;
private static final boolean DEBUG_CONFIG = false;
+ private static final boolean DEBUG_ATTRIBUTES_CACHE = false;
private static final boolean TRACE_FOR_PRELOAD = false;
private static final boolean TRACE_FOR_MISS_PRELOAD = false;
@@ -104,6 +105,7 @@
private boolean mPreloading;
/*package*/ TypedArray mCachedStyledAttributes = null;
+ RuntimeException mLastRetrievedAttrs = null;
private int mLastCachedXmlBlockIndex = -1;
private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
@@ -2167,6 +2169,10 @@
TypedArray attrs = mCachedStyledAttributes;
if (attrs != null) {
mCachedStyledAttributes = null;
+ if (DEBUG_ATTRIBUTES_CACHE) {
+ mLastRetrievedAttrs = new RuntimeException("here");
+ mLastRetrievedAttrs.fillInStackTrace();
+ }
attrs.mLength = len;
int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
@@ -2177,6 +2183,15 @@
attrs.mIndices = new int[1+len];
return attrs;
}
+ if (DEBUG_ATTRIBUTES_CACHE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ if (mLastRetrievedAttrs != null) {
+ Log.i(TAG, "Allocated new TypedArray of " + len + " in " + this, here);
+ Log.i(TAG, "Last retrieved attributes here", mLastRetrievedAttrs);
+ }
+ mLastRetrievedAttrs = here;
+ }
return new TypedArray(this,
new int[len*AssetManager.STYLE_NUM_ENTRIES],
new int[1+len], len);
diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java
index 5cfa998..25c0c99 100644
--- a/core/java/android/inputmethodservice/ExtractEditLayout.java
+++ b/core/java/android/inputmethodservice/ExtractEditLayout.java
@@ -16,9 +16,6 @@
package android.inputmethodservice;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuPopupHelper;
-
import android.content.Context;
import android.util.AttributeSet;
import android.view.ActionMode;
@@ -29,6 +26,9 @@
import android.widget.Button;
import android.widget.LinearLayout;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuPopupHelper;
+
/**
* ExtractEditLayout provides an ActionMode presentation for the
* limited screen real estate in extract mode.
@@ -61,6 +61,22 @@
return null;
}
+ /**
+ * @return true if an action mode is currently active.
+ */
+ public boolean isActionModeStarted() {
+ return mActionMode != null;
+ }
+
+ /**
+ * Finishes a possibly started action mode.
+ */
+ public void finishActionMode() {
+ if (mActionMode != null) {
+ mActionMode.finish();
+ }
+ }
+
@Override
public void onFinishInflate() {
super.onFinishInflate();
@@ -92,7 +108,7 @@
@Override
public void setTitle(int resId) {
- // Title will nor be shown.
+ // Title will not be shown.
}
@Override
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7d3cd92..d2effff 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -637,6 +637,7 @@
* configuration change happens.
*/
public void onInitializeInterface() {
+ // Intentionally empty
}
void initialize() {
@@ -687,6 +688,10 @@
mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
mInsetsComputer);
if (mWindowAdded) {
+ // Disable exit animation for the current IME window
+ // to avoid the race condition between the exit and enter animations
+ // when the current IME is being switched to another one.
+ mWindow.getWindow().setWindowAnimations(0);
mWindow.dismiss();
}
}
@@ -876,8 +881,7 @@
}
if (changed) {
- onConfigureWindow(mWindow.getWindow(), isFullscreen,
- !mShowInputRequested);
+ onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
mLastShowInputRequested = mShowInputRequested;
}
}
@@ -935,7 +939,7 @@
}
return true;
}
-
+
/**
* Controls the visibility of the extracted text area. This only applies
* when the input method is in fullscreen mode, and thus showing extracted
@@ -1242,6 +1246,7 @@
* same text field as before.
*/
public void onStartInputView(EditorInfo info, boolean restarting) {
+ // Intentionally empty
}
/**
@@ -1286,6 +1291,7 @@
* same text field as before.
*/
public void onStartCandidatesView(EditorInfo info, boolean restarting) {
+ // Intentionally empty
}
/**
@@ -1455,6 +1461,7 @@
* for the window has occurred (creating its views etc).
*/
public void onWindowShown() {
+ // Intentionally empty
}
/**
@@ -1462,6 +1469,7 @@
* after previously being visible.
*/
public void onWindowHidden() {
+ // Intentionally empty
}
/**
@@ -1472,6 +1480,7 @@
* and {@link #getCurrentInputConnection} return valid objects.
*/
public void onBindInput() {
+ // Intentionally empty
}
/**
@@ -1481,6 +1490,7 @@
* valid objects.
*/
public void onUnbindInput() {
+ // Intentionally empty
}
/**
@@ -1496,6 +1506,7 @@
* session with the editor.
*/
public void onStartInput(EditorInfo attribute, boolean restarting) {
+ // Intentionally empty
}
void doFinishInput() {
@@ -1570,6 +1581,7 @@
* <p>The default implementation here does nothing.
*/
public void onDisplayCompletions(CompletionInfo[] completions) {
+ // Intentionally empty
}
/**
@@ -1626,6 +1638,7 @@
* @param focusChanged true if the user changed the focused view by this click.
*/
public void onViewClicked(boolean focusChanged) {
+ // Intentionally empty
}
/**
@@ -1634,6 +1647,7 @@
* The default implementation does nothing.
*/
public void onUpdateCursor(Rect newCursor) {
+ // Intentionally empty
}
/**
@@ -1664,6 +1678,13 @@
private boolean handleBack(boolean doIt) {
if (mShowInputRequested) {
+ if (isExtractViewShown() && mExtractView instanceof ExtractEditLayout) {
+ ExtractEditLayout extractEditLayout = (ExtractEditLayout) mExtractView;
+ if (extractEditLayout.isActionModeStarted()) {
+ if (doIt) extractEditLayout.finishActionMode();
+ return true;
+ }
+ }
// If the soft input area is shown, back closes it and we
// consume the back key.
if (doIt) requestHideSelf(0);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 65c1bd5..bcf6239 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -394,7 +394,7 @@
&& lastReason != null)
reason = lastReason;
mNetworkInfo.setDetailedState(state, reason, extraInfo);
- Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo));
msg.sendToTarget();
}
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index d07d899..d8ac31f 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.MathUtils;
import java.io.CharArrayWriter;
import java.io.DataInputStream;
@@ -207,6 +208,34 @@
}
/**
+ * Return index of bucket that contains or is immediately before the
+ * requested time.
+ */
+ public int getIndexBefore(long time) {
+ int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
+ if (index < 0) {
+ index = (~index) - 1;
+ } else {
+ index -= 1;
+ }
+ return MathUtils.constrain(index, 0, bucketCount - 1);
+ }
+
+ /**
+ * Return index of bucket that contains or is immediately after the
+ * requested time.
+ */
+ public int getIndexAfter(long time) {
+ int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
+ if (index < 0) {
+ index = ~index;
+ } else {
+ index += 1;
+ }
+ return MathUtils.constrain(index, 0, bucketCount - 1);
+ }
+
+ /**
* Return specific stats entry.
*/
public Entry getValues(int i, Entry recycle) {
@@ -247,7 +276,8 @@
// distribute data usage into buckets
long duration = end - start;
- for (int i = bucketCount - 1; i >= 0; i--) {
+ final int startIndex = getIndexAfter(end);
+ for (int i = startIndex; i >= 0; i--) {
final long curStart = bucketStart[i];
final long curEnd = curStart + bucketDuration;
@@ -406,7 +436,8 @@
entry.txPackets = txPackets != null ? 0 : UNKNOWN;
entry.operations = operations != null ? 0 : UNKNOWN;
- for (int i = bucketCount - 1; i >= 0; i--) {
+ final int startIndex = getIndexAfter(end);
+ for (int i = startIndex; i >= 0; i--) {
final long curStart = bucketStart[i];
final long curEnd = curStart + bucketDuration;
@@ -417,8 +448,14 @@
// include full value for active buckets, otherwise only fractional
final boolean activeBucket = curStart < now && curEnd > now;
- final long overlap = activeBucket ? bucketDuration
- : Math.min(curEnd, end) - Math.max(curStart, start);
+ final long overlap;
+ if (activeBucket) {
+ overlap = bucketDuration;
+ } else {
+ final long overlapEnd = curEnd < end ? curEnd : end;
+ final long overlapStart = curStart > start ? curStart : start;
+ overlap = overlapEnd - overlapStart;
+ }
if (overlap <= 0) continue;
// integer math each time is faster than floating point
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index ec3b1e1..47cfa73 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -104,14 +104,6 @@
return NetworkManagementSocketTagger.getThreadSocketStatsTag();
}
- /**
- * @deprecated unsupported, will eventually be removed
- */
- @Deprecated
- public static void setThreadStatsTag(String tag) {
- setThreadStatsTag(tag.hashCode());
- }
-
public static void clearThreadStatsTag() {
NetworkManagementSocketTagger.setThreadSocketStatsTag(-1);
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
old mode 100644
new mode 100755
index 6585e82..e849b71
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1798,6 +1798,20 @@
public static final String ROAMING_PROTOCOL = "roaming_protocol";
public static final String CURRENT = "current";
+
+ /**
+ * Current status of APN
+ * true : enabled APN, false : disabled APN.
+ */
+ public static final String CARRIER_ENABLED = "carrier_enabled";
+
+ /**
+ * Radio Access Technology info
+ * To check what values can hold, refer to ServiceState.java.
+ * This should be spread to other technologies,
+ * but currently only used for LTE(14) and EHRPD(13).
+ */
+ public static final String BEARER = "bearer";
}
public static final class Intents {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 56da69d..1b473ec 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -401,6 +401,7 @@
Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
} else if (name.equals("Alias")) {
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
@@ -410,6 +411,7 @@
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(Integer.valueOf(propValues[1])));
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
} else if (name.equals("Connected")) {
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
@@ -425,6 +427,7 @@
intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
}
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
} else if (name.equals("UUIDs")) {
String uuid = null;
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 00d3331..f0fb4e0 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -145,7 +145,7 @@
private final ArrayList<String> mUuidIntentTracker;
private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
- private final HashMap<Integer, Integer> mServiceRecordToPid;
+ private final HashMap<Integer, Pair<Integer, IBinder>> mServiceRecordToPid;
private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
private final BluetoothProfileState mA2dpProfileState;
@@ -221,7 +221,7 @@
mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
mUuidIntentTracker = new ArrayList<String>();
mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
- mServiceRecordToPid = new HashMap<Integer, Integer>();
+ mServiceRecordToPid = new HashMap<Integer, Pair<Integer, IBinder>>();
mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
@@ -1516,10 +1516,10 @@
}
int pid = Binder.getCallingPid();
- mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
+ mServiceRecordToPid.put(new Integer(handle), new Pair<Integer, IBinder>(pid, b));
try {
b.linkToDeath(new Reaper(handle, pid, RFCOMM_RECORD_REAPER), 0);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
return handle;
}
@@ -1532,12 +1532,12 @@
}
private synchronized void checkAndRemoveRecord(int handle, int pid) {
- Integer handleInt = new Integer(handle);
- Integer owner = mServiceRecordToPid.get(handleInt);
+ Pair<Integer, IBinder> pidPair = mServiceRecordToPid.get(handle);
+ Integer owner = pidPair.first;
if (owner != null && pid == owner.intValue()) {
if (DBG) Log.d(TAG, "Removing service record " +
Integer.toHexString(handle) + " for pid " + pid);
- mServiceRecordToPid.remove(handleInt);
+ mServiceRecordToPid.remove(handle);
removeServiceRecordNative(handle);
}
}
@@ -1593,6 +1593,7 @@
try {
binder.linkToDeath(new Reaper(pid, STATE_CHANGE_REAPER), 0);
} catch (RemoteException e) {
+ Log.e(TAG, "", e);
return false;
}
}
@@ -1867,7 +1868,7 @@
private void dumpApplicationServiceRecords(PrintWriter pw) {
pw.println("\n--Application Service Records--");
for (Integer handle : mServiceRecordToPid.keySet()) {
- Integer pid = mServiceRecordToPid.get(handle);
+ Integer pid = mServiceRecordToPid.get(handle).first;
pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
}
mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index 75dcd6e..d970ae6 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -450,6 +450,19 @@
*/
private static final long MIN_SLEEP_TIME_MS = 20;
+ /**
+ * The maximum increment of time to sleep while waiting for an audiotrack
+ * to finish playing.
+ */
+ private static final long MAX_SLEEP_TIME_MS = 2500;
+
+ /**
+ * The maximum amount of time to wait for an audio track to make progress while
+ * it remains in PLAYSTATE_PLAYING. This should never happen in normal usage, but
+ * could happen in exceptional circumstances like a media_server crash.
+ */
+ private static final long MAX_PROGRESS_WAIT_MS = MAX_SLEEP_TIME_MS;
+
private static void blockUntilDone(SynthesisMessageParams params) {
if (params.mAudioTrack == null || params.mBytesWritten <= 0) {
return;
@@ -490,16 +503,34 @@
final AudioTrack audioTrack = params.mAudioTrack;
final int lengthInFrames = params.mBytesWritten / params.mBytesPerFrame;
+ int previousPosition = -1;
int currentPosition = 0;
- while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
- if (audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
- break;
- }
+ long blockedTimeMs = 0;
+
+ while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames &&
+ audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
final long estimatedTimeMs = ((lengthInFrames - currentPosition) * 1000) /
audioTrack.getSampleRate();
+ final long sleepTimeMs = clip(estimatedTimeMs, MIN_SLEEP_TIME_MS, MAX_SLEEP_TIME_MS);
- final long sleepTimeMs = Math.max(estimatedTimeMs, MIN_SLEEP_TIME_MS);
+ // Check if the audio track has made progress since the last loop
+ // iteration. We should then add in the amount of time that was
+ // spent sleeping in the last iteration.
+ if (currentPosition == previousPosition) {
+ // This works only because the sleep time that would have been calculated
+ // would be the same in the previous iteration too.
+ blockedTimeMs += sleepTimeMs;
+ // If we've taken too long to make progress, bail.
+ if (blockedTimeMs > MAX_PROGRESS_WAIT_MS) {
+ Log.w(TAG, "Waited unsuccessfully for " + MAX_PROGRESS_WAIT_MS + "ms " +
+ "for AudioTrack to make progress, Aborting");
+ break;
+ }
+ } else {
+ blockedTimeMs = 0;
+ }
+ previousPosition = currentPosition;
if (DBG) Log.d(TAG, "About to sleep for : " + sleepTimeMs + " ms," +
" Playback position : " + currentPosition + ", Length in frames : "
@@ -512,6 +543,18 @@
}
}
+ private static final long clip(long value, long min, long max) {
+ if (value < min) {
+ return min;
+ }
+
+ if (value > max) {
+ return max;
+ }
+
+ return value;
+ }
+
private static AudioTrack createStreamingAudioTrack(SynthesisMessageParams params) {
final int channelConfig = getChannelConfig(params.mChannelCount);
final int sampleRateInHz = params.mSampleRateInHz;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 68a6b3e..a52d48e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -723,7 +723,7 @@
float ret = 0;
int contextLen = contextEnd - contextStart;
- if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) {
+ if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
if (mCharsValid) {
ret = wp.getTextRunAdvances(mChars, start, runLen,
@@ -753,7 +753,7 @@
wp.setColor(previousColor);
}
- if (wp.underlineCount != 0) {
+ if (wp.underlineColor != 0) {
// kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();
@@ -764,11 +764,8 @@
wp.setStyle(Paint.Style.FILL);
wp.setAntiAlias(true);
- for (int i = 0; i < wp.underlineCount; i++) {
- wp.setColor(wp.underlineColors[i]);
- c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i],
- wp);
- }
+ wp.setColor(wp.underlineColor);
+ c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp);
wp.setStyle(previousStyle);
wp.setColor(previousColor);
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index afd9892..0447117 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -24,8 +24,6 @@
*/
public class TextPaint extends Paint {
- private static final int DEFAULT_UNDERLINE_SIZE = 3;
-
// Special value 0 means no background paint
public int bgColor;
public int baselineShift;
@@ -36,17 +34,12 @@
* Special value 0 means no custom underline
* @hide
*/
- public int[] underlineColors;
+ public int underlineColor = 0;
/**
* Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
* @hide
*/
- public float[] underlineThicknesses;
- /**
- * The number of underlines currently stored in the array. If 0, no underline is drawn.
- * @hide
- */
- public int underlineCount;
+ public float underlineThickness;
public TextPaint() {
super();
@@ -72,16 +65,8 @@
linkColor = tp.linkColor;
drawableState = tp.drawableState;
density = tp.density;
-
- if (tp.underlineColors != null) {
- if (underlineColors == null || underlineColors.length < tp.underlineCount) {
- underlineColors = new int[tp.underlineCount];
- underlineThicknesses = new float[tp.underlineCount];
- }
- System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount);
- System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount);
- }
- underlineCount = tp.underlineCount;
+ underlineColor = tp.underlineColor;
+ underlineThickness = tp.underlineThickness;
}
/**
@@ -91,31 +76,7 @@
* @hide
*/
public void setUnderlineText(int color, float thickness) {
- if (color == 0) {
- // No underline
- return;
- }
-
- if (underlineCount == 0) {
- underlineColors = new int[DEFAULT_UNDERLINE_SIZE];
- underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE];
- underlineColors[underlineCount] = color;
- underlineThicknesses[underlineCount] = thickness;
- underlineCount++;
- } else {
- if (underlineCount == underlineColors.length) {
- int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE];
- float[] newThickness = new float[underlineThicknesses.length
- + DEFAULT_UNDERLINE_SIZE];
- System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length);
- System.arraycopy(
- underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length);
- underlineColors = newColors;
- underlineThicknesses = newThickness;
- }
- underlineColors[underlineCount] = color;
- underlineThicknesses[underlineCount] = thickness;
- underlineCount++;
- }
+ underlineColor = color;
+ underlineThickness = thickness;
}
}
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 51e9d7d..1379dd2d 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -108,7 +108,8 @@
/**
* @param context Context for the application
* @param locale locale Locale of the suggestions
- * @param suggestions Suggestions for the string under the span
+ * @param suggestions Suggestions for the string under the span. Only the first up to
+ * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered.
* @param flags Additional flags indicating how this span is handled in TextView
* @param notificationTargetClass if not null, this class will get notified when the user
* selects one of the suggestions.
@@ -258,10 +259,16 @@
@Override
public void updateDrawState(TextPaint tp) {
- if ((mFlags & FLAG_MISSPELLED) != 0) {
- tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
- } else if ((mFlags & FLAG_EASY_CORRECT) != 0) {
- tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+ final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
+ final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+ if (easy) {
+ if (!misspelled) {
+ tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+ } else if (tp.underlineColor == 0) {
+ // Spans are rendered in an arbitrary order. Since misspelled is less prioritary
+ // than just easy, do not apply misspelled if an easy (or a mispelled) has been set
+ tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+ }
}
}
@@ -272,8 +279,15 @@
*/
public int getUnderlineColor() {
// The order here should match what is used in updateDrawState
- if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor;
- if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor;
+ final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
+ final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+ if (easy) {
+ if (!misspelled) {
+ return mEasyCorrectUnderlineColor;
+ } else {
+ return mMisspelledUnderlineColor;
+ }
+ }
return 0;
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eedf19f..65e9857 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,7 +27,6 @@
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
-import android.graphics.Matrix.ScaleToFit;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -2272,8 +2271,6 @@
*/
int mOldHeightMeasureSpec = Integer.MIN_VALUE;
- private Resources mResources = null;
-
private Drawable mBGDrawable;
private int mBackgroundResource;
@@ -2336,6 +2333,8 @@
*/
protected Context mContext;
+ private final Resources mResources;
+
private ScrollabilityCache mScrollCache;
private int[] mDrawableState = null;
@@ -2552,6 +2551,11 @@
private boolean mSendingHoverAccessibilityEvents;
/**
+ * Delegate for injecting accessiblity functionality.
+ */
+ AccessibilityDelegate mAccessibilityDelegate;
+
+ /**
* Text direction is inherited thru {@link ViewGroup}
* @hide
*/
@@ -3012,6 +3016,8 @@
}
}
+ a.recycle();
+
setOverScrollMode(overScrollMode);
if (background != null) {
@@ -3069,14 +3075,13 @@
}
computeOpaqueFlags();
-
- a.recycle();
}
/**
* Non-public constructor for use in testing
*/
View() {
+ mResources = null;
}
/**
@@ -3774,14 +3779,34 @@
* and last calls
* {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
* on its parent to resuest sending of the event to interested parties.
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is
+ * responsible for handling this call.
+ * </p>
*
* @param eventType The type of the event to send.
*
* @see #onInitializeAccessibilityEvent(AccessibilityEvent)
* @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
* @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)
+ * @see AccessibilityDelegate
*/
public void sendAccessibilityEvent(int eventType) {
+ if (mAccessibilityDelegate != null) {
+ mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
+ } else {
+ sendAccessibilityEventInternal(eventType);
+ }
+ }
+
+ /**
+ * @see #sendAccessibilityEvent(int)
+ *
+ * Note: Called from the default {@link AccessibilityDelegate}.
+ */
+ void sendAccessibilityEventInternal(int eventType) {
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
}
@@ -3790,13 +3815,32 @@
/**
* This method behaves exactly as {@link #sendAccessibilityEvent(int)} but
* takes as an argument an empty {@link AccessibilityEvent} and does not
- * perfrom a check whether accessibility is enabled.
+ * perform a check whether accessibility is enabled.
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)}
+ * is responsible for handling this call.
+ * </p>
*
* @param event The event to send.
*
* @see #sendAccessibilityEvent(int)
*/
public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+ if (mAccessibilityDelegate != null) {
+ mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
+ } else {
+ sendAccessibilityEventUncheckedInternal(event);
+ }
+ }
+
+ /**
+ * @see #sendAccessibilityEventUnchecked(AccessibilityEvent)
+ *
+ * Note: Called from the default {@link AccessibilityDelegate}.
+ */
+ void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
if (!isShown()) {
return;
}
@@ -3811,18 +3855,36 @@
* to its children for adding their text content to the event. Note that the
* event text is populated in a separate dispatch path since we add to the
* event not only the text of the source but also the text of all its descendants.
- * </p>
* A typical implementation will call
* {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view
* and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
* on each child. Override this method if custom population of the event text
* content is required.
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)}
+ * is responsible for handling this call.
+ * </p>
*
* @param event The event.
*
* @return True if the event population was completed.
*/
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ if (mAccessibilityDelegate != null) {
+ return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event);
+ } else {
+ return dispatchPopulateAccessibilityEventInternal(event);
+ }
+ }
+
+ /**
+ * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ *
+ * Note: Called from the default {@link AccessibilityDelegate}.
+ */
+ boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
onPopulateAccessibilityEvent(event);
return false;
}
@@ -3845,6 +3907,12 @@
* event.getText().add(selectedDateUtterance);
* }
* </code></pre></p>
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)}
+ * is responsible for handling this call.
+ * </p>
*
* @param event The accessibility event which to populate.
*
@@ -3852,13 +3920,27 @@
* @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
*/
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ if (mAccessibilityDelegate != null) {
+ mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
+ } else {
+ onPopulateAccessibilityEventInternal(event);
+ }
}
/**
- * Initializes an {@link AccessibilityEvent} with information about the
- * the type of the event and this View which is the event source. In other
- * words, the source of an accessibility event is the view whose state
- * change triggered firing the event.
+ * @see #onPopulateAccessibilityEvent(AccessibilityEvent)
+ *
+ * Note: Called from the default {@link AccessibilityDelegate}.
+ */
+ void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+
+ }
+
+ /**
+ * Initializes an {@link AccessibilityEvent} with information about
+ * this View which is the event source. In other words, the source of
+ * an accessibility event is the view whose state change triggered firing
+ * the event.
* <p>
* Example: Setting the password property of an event in addition
* to properties set by the super implementation.
@@ -3868,12 +3950,32 @@
* event.setPassword(true);
* }
* </code></pre></p>
- * @param event The event to initialeze.
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)}
+ * is responsible for handling this call.
+ * </p>
+ *
+ * @param event The event to initialize.
*
* @see #sendAccessibilityEvent(int)
* @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
*/
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ if (mAccessibilityDelegate != null) {
+ mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
+ } else {
+ onInitializeAccessibilityEventInternal(event);
+ }
+ }
+
+ /**
+ * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
+ *
+ * Note: Called from the default {@link AccessibilityDelegate}.
+ */
+ void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
event.setSource(this);
event.setClassName(getClass().getName());
event.setPackageName(getContext().getPackageName());
@@ -3942,9 +4044,29 @@
* Subclasses should override this method, call the super implementation,
* and set additional attributes.
* </p>
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}
+ * is responsible for handling this call.
+ * </p>
+ *
* @param info The instance to initialize.
*/
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ if (mAccessibilityDelegate != null) {
+ mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
+ } else {
+ onInitializeAccessibilityNodeInfoInternal(info);
+ }
+ }
+
+ /**
+ * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+ *
+ * Note: Called from the default {@link AccessibilityDelegate}.
+ */
+ void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Rect bounds = mAttachInfo.mTmpInvalRect;
getDrawingRect(bounds);
info.setBoundsInParent(bounds);
@@ -3988,6 +4110,19 @@
}
/**
+ * Sets a delegate for implementing accessibility support via compositon as
+ * opposed to inheritance. The delegate's primary use is for implementing
+ * backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
+ *
+ * @param delegate The delegate instance.
+ *
+ * @see AccessibilityDelegate
+ */
+ public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+ mAccessibilityDelegate = delegate;
+ }
+
+ /**
* Gets the unique identifier of this view on the screen for accessibility purposes.
* If this {@link View} is not attached to any window, {@value #NO_ID} is returned.
*
@@ -10192,7 +10327,7 @@
/**
* Setting a solid background color for the drawing cache's bitmaps will improve
- * perfromance and memory usage. Note, though that this should only be used if this
+ * performance and memory usage. Note, though that this should only be used if this
* view will always be drawn on top of a solid color.
*
* @param color The background color to use for the drawing cache's bitmap
@@ -13039,6 +13174,10 @@
shadowSize.x, shadowSize.y,
shadowTouchPoint.x, shadowTouchPoint.y, data);
if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
+
+ // Off and running! Release our local surface instance; the drag
+ // shadow surface is now managed by the system process.
+ surface.release();
}
} catch (Exception e) {
Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
@@ -14417,4 +14556,205 @@
mIsPending = false;
}
}
+
+ /**
+ * <p>
+ * This class represents a delegate that can be registered in a {@link View}
+ * to enhance accessibility support via composition rather via inheritance.
+ * It is specifically targeted to widget developers that extend basic View
+ * classes i.e. classes in package android.view, that would like their
+ * applications to be backwards compatible.
+ * </p>
+ * <p>
+ * A scenario in which a developer would like to use an accessibility delegate
+ * is overriding a method introduced in a later API version then the minimal API
+ * version supported by the application. For example, the method
+ * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available
+ * in API version 4 when the accessibility APIs were first introduced. If a
+ * developer would like his application to run on API version 4 devices (assuming
+ * all other APIs used by the application are version 4 or lower) and take advantage
+ * of this method, instead of overriding the method which would break the application's
+ * backwards compatibility, he can override the corresponding method in this
+ * delegate and register the delegate in the target View if the API version of
+ * the system is high enough i.e. the API version is same or higher to the API
+ * version that introduced
+ * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}.
+ * </p>
+ * <p>
+ * Here is an example implementation:
+ * </p>
+ * <code><pre><p>
+ * if (Build.VERSION.SDK_INT >= 14) {
+ * // If the API version is equal of higher than the version in
+ * // which onInitializeAccessibilityNodeInfo was introduced we
+ * // register a delegate with a customized implementation.
+ * View view = findViewById(R.id.view_id);
+ * view.setAccessibilityDelegate(new AccessibilityDelegate() {
+ * public void onInitializeAccessibilityNodeInfo(View host,
+ * AccessibilityNodeInfo info) {
+ * // Let the default implementation populate the info.
+ * super.onInitializeAccessibilityNodeInfo(host, info);
+ * // Set some other information.
+ * info.setEnabled(host.isEnabled());
+ * }
+ * });
+ * }
+ * </code></pre></p>
+ * <p>
+ * This delegate contains methods that correspond to the accessibility methods
+ * in View. If a delegate has been specified the implementation in View hands
+ * off handling to the corresponding method in this delegate. The default
+ * implementation the delegate methods behaves exactly as the corresponding
+ * method in View for the case of no accessibility delegate been set. Hence,
+ * to customize the behavior of a View method, clients can override only the
+ * corresponding delegate method without altering the behavior of the rest
+ * accessibility related methods of the host view.
+ * </p>
+ */
+ public static class AccessibilityDelegate {
+
+ /**
+ * Sends an accessibility event of the given type. If accessibility is not
+ * enabled this method has no effect.
+ * <p>
+ * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
+ * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
+ * been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param eventType The type of the event to send.
+ *
+ * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
+ */
+ public void sendAccessibilityEvent(View host, int eventType) {
+ host.sendAccessibilityEventInternal(eventType);
+ }
+
+ /**
+ * Sends an accessibility event. This method behaves exactly as
+ * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
+ * empty {@link AccessibilityEvent} and does not perform a check whether
+ * accessibility is enabled.
+ * <p>
+ * The default implementation behaves as
+ * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+ * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
+ * the case of no accessibility delegate been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param event The event to send.
+ *
+ * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+ * View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+ */
+ public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
+ host.sendAccessibilityEventUncheckedInternal(event);
+ }
+
+ /**
+ * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
+ * to its children for adding their text content to the event.
+ * <p>
+ * The default implementation behaves as
+ * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
+ * the case of no accessibility delegate been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param event The event.
+ * @return True if the event population was completed.
+ *
+ * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ */
+ public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ return host.dispatchPopulateAccessibilityEventInternal(event);
+ }
+
+ /**
+ * Gives a chance to the host View to populate the accessibility event with its
+ * text content.
+ * <p>
+ * The default implementation behaves as
+ * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for
+ * the case of no accessibility delegate been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param event The accessibility event which to populate.
+ *
+ * @see View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ */
+ public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ host.onPopulateAccessibilityEventInternal(event);
+ }
+
+ /**
+ * Initializes an {@link AccessibilityEvent} with information about the
+ * the host View which is the event source.
+ * <p>
+ * The default implementation behaves as
+ * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)
+ * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for
+ * the case of no accessibility delegate been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param event The event to initialize.
+ *
+ * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
+ * View#onInitializeAccessibilityEvent(AccessibilityEvent)
+ */
+ public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+ host.onInitializeAccessibilityEventInternal(event);
+ }
+
+ /**
+ * Initializes an {@link AccessibilityNodeInfo} with information about the host view.
+ * <p>
+ * The default implementation behaves as
+ * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+ * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for
+ * the case of no accessibility delegate been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param info The instance to initialize.
+ *
+ * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+ * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+ */
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ host.onInitializeAccessibilityNodeInfoInternal(info);
+ }
+
+ /**
+ * Called when a child of the host View has requested sending an
+ * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
+ * to augment the event.
+ * <p>
+ * The default implementation behaves as
+ * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+ * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for
+ * the case of no accessibility delegate been set.
+ * </p>
+ *
+ * @param host The View hosting the delegate.
+ * @param child The child which requests sending the event.
+ * @param event The event to be sent.
+ * @return True if the event should be sent
+ *
+ * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+ * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+ */
+ public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+ AccessibilityEvent event) {
+ return host.onRequestSendAccessibilityEventInternal(child, event);
+ }
+ }
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0e420d6..1bd0782 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -34,6 +34,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
+import android.view.View.AccessibilityDelegate;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation;
@@ -606,6 +607,12 @@
/**
* Called when a child has requested sending an {@link AccessibilityEvent} and
* gives an opportunity to its parent to augment the event.
+ * <p>
+ * If an {@link AccessibilityDelegate} has been specified via calling
+ * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+ * {@link AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
+ * is responsible for handling this call.
+ * </p>
*
* @param child The child which requests sending the event.
* @param event The event to be sent.
@@ -614,6 +621,19 @@
* @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
*/
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ if (mAccessibilityDelegate != null) {
+ return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
+ } else {
+ return onRequestSendAccessibilityEventInternal(child, event);
+ }
+ }
+
+ /**
+ * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+ *
+ * Note: Called from the default {@link View.AccessibilityDelegate}.
+ */
+ boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
return true;
}
@@ -2142,9 +2162,9 @@
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
// We first get a chance to populate the event.
- onPopulateAccessibilityEvent(event);
+ super.dispatchPopulateAccessibilityEventInternal(event);
// Let our children have a shot in populating the event.
for (int i = 0, count = getChildCount(); i < count; i++) {
View child = getChildAt(i);
@@ -2159,8 +2179,8 @@
}
@Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
+ void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfoInternal(info);
// If the view is not the topmost one in the view hierarchy and it is
// marked as the logical root of a view hierarchy, do not go any deeper.
if ((!(getParent() instanceof ViewRootImpl)) && (mPrivateFlags & IS_ROOT_NAMESPACE) != 0) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fb3f6e8..81f9d78 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -164,11 +164,14 @@
final W mWindow;
+ final int mTargetSdkVersion;
+
View mView;
View mFocusedView;
View mRealFocusedView; // this is not set to null in touch mode
int mViewVisibility;
boolean mAppVisible = true;
+ int mOrigWindowType = -1;
// Set to true if the owner of this window is in the stopped state,
// so the window should no longer be active.
@@ -331,6 +334,7 @@
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
+ mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mInputMethodCallback = new InputMethodCallback(this);
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
@@ -461,6 +465,7 @@
mInputChannel = new InputChannel();
}
try {
+ mOrigWindowType = mWindowAttributes.type;
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
@@ -3481,6 +3486,14 @@
}
mPendingConfiguration.seq = 0;
//Log.d(TAG, ">>>>>> CALLING relayout");
+ if (params != null && mOrigWindowType != params.type) {
+ // For compatibility with old apps, don't crash here.
+ if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ Slog.w(TAG, "Window type can not be changed after "
+ + "the window is added; ignoring change of " + mView);
+ params.type = mOrigWindowType;
+ }
+ }
int relayoutResult = sWindowSession.relayout(
mWindow, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index c1eec6f..0d57c9b 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -232,11 +232,6 @@
setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
- final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
- if (resID > 0) {
- setInterpolator(context, resID);
- }
-
setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
@@ -245,10 +240,16 @@
setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
-
- ensureInterpolator();
+
+ final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
a.recycle();
+
+ if (resID > 0) {
+ setInterpolator(context, resID);
+ }
+
+ ensureInterpolator();
}
@Override
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 77f6776..9c44138 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -643,10 +643,10 @@
/**
* Set whether the WebView will enable smooth transition while panning or
- * zooming. If it is true, WebView will choose a solution to maximize the
- * performance. e.g. the WebView's content may not be updated during the
- * transition. If it is false, WebView will keep its fidelity. The default
- * value is false.
+ * zooming or while the window hosting the WebView does not have focus.
+ * If it is true, WebView will choose a solution to maximize the performance.
+ * e.g. the WebView's content may not be updated during the transition.
+ * If it is false, WebView will keep its fidelity. The default value is false.
*/
public void setEnableSmoothTransition(boolean enable) {
mEnableSmoothTransition = enable;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 47abbc2..2f73474 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -908,6 +908,9 @@
// used for serializing asynchronously handled touch events.
private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
+ // Used to track whether picture updating was paused due to a window focus change.
+ private boolean mPictureUpdatePausedForFocusChange = false;
+
// Used to notify listeners of a new picture.
private PictureListener mPictureListener;
/**
@@ -4018,7 +4021,14 @@
@Override
protected void finalize() throws Throwable {
try {
- destroyImpl();
+ if (mNativeClass != 0) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ destroy();
+ }
+ });
+ }
} finally {
super.finalize();
}
@@ -5570,8 +5580,18 @@
setActive(hasWindowFocus);
if (hasWindowFocus) {
JWebCoreJavaBridge.setActiveWebView(this);
+ if (mPictureUpdatePausedForFocusChange) {
+ WebViewCore.resumeUpdatePicture(mWebViewCore);
+ mPictureUpdatePausedForFocusChange = false;
+ }
} else {
JWebCoreJavaBridge.removeActiveWebView(this);
+ final WebSettings settings = getSettings();
+ if (settings != null && settings.enableSmoothTransition() &&
+ mWebViewCore != null && !WebViewCore.isUpdatePicturePaused(mWebViewCore)) {
+ WebViewCore.pauseUpdatePicture(mWebViewCore);
+ mPictureUpdatePausedForFocusChange = true;
+ }
}
super.onWindowFocusChanged(hasWindowFocus);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c61bd48..48359d44 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2085,6 +2085,10 @@
if (!core.getSettings().enableSmoothTransition()) return;
synchronized (core) {
+ if (core.mNativeClass == 0) {
+ Log.w(LOGTAG, "Cannot pauseUpdatePicture, core destroyed or not initialized!");
+ return;
+ }
core.nativeSetIsPaused(true);
core.mDrawIsPaused = true;
}
@@ -2099,6 +2103,10 @@
return;
synchronized (core) {
+ if (core.mNativeClass == 0) {
+ Log.w(LOGTAG, "Cannot resumeUpdatePicture, core destroyed!");
+ return;
+ }
core.nativeSetIsPaused(false);
core.mDrawIsPaused = false;
// always redraw on resume to reenable gif animations
@@ -2107,6 +2115,10 @@
}
}
+ static boolean isUpdatePicturePaused(WebViewCore core) {
+ return core != null ? core.mDrawIsPaused : false;
+ }
+
//////////////////////////////////////////////////////////////////////////
private void restoreState(int index) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 05d4f05..5642b7b 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2576,13 +2576,11 @@
final int longPressPosition, final long longPressId) {
// CHOICE_MODE_MULTIPLE_MODAL takes over long press.
if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
- if (mChoiceActionMode == null) {
- mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
+ if (mChoiceActionMode == null &&
+ (mChoiceActionMode = startActionMode(mMultiChoiceModeCallback)) != null) {
setItemChecked(longPressPosition, true);
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
}
- // TODO Should we select the long pressed item if we were already in
- // selection mode? (i.e. treat it like an item click?)
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
@@ -2771,15 +2769,21 @@
}
}
- private boolean startScrollIfNeeded(int deltaY) {
+ private boolean startScrollIfNeeded(int y) {
// Check if we have moved far enough that it looks more like a
// scroll than a tap
+ final int deltaY = y - mMotionY;
final int distance = Math.abs(deltaY);
final boolean overscroll = mScrollY != 0;
if (overscroll || distance > mTouchSlop) {
createScrollingCache();
- mTouchMode = overscroll ? TOUCH_MODE_OVERSCROLL : TOUCH_MODE_SCROLL;
- mMotionCorrection = deltaY;
+ if (overscroll) {
+ mTouchMode = TOUCH_MODE_OVERSCROLL;
+ mMotionCorrection = 0;
+ } else {
+ mTouchMode = TOUCH_MODE_SCROLL;
+ mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
+ }
final Handler handler = getHandler();
// Handler should not be null unless the AbsListView is not attached to a
// window, which would make it very hard to scroll it... but the monkeys
@@ -2799,12 +2803,176 @@
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
+ scrollIfNeeded(y);
return true;
}
return false;
}
+ private void scrollIfNeeded(int y) {
+ final int rawDeltaY = y - mMotionY;
+ final int deltaY = rawDeltaY - mMotionCorrection;
+ int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
+
+ if (mTouchMode == TOUCH_MODE_SCROLL) {
+ if (PROFILE_SCROLLING) {
+ if (!mScrollProfilingStarted) {
+ Debug.startMethodTracing("AbsListViewScroll");
+ mScrollProfilingStarted = true;
+ }
+ }
+
+ if (mScrollStrictSpan == null) {
+ // If it's non-null, we're already in a scroll.
+ mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
+ }
+
+ if (y != mLastY) {
+ // We may be here after stopping a fling and continuing to scroll.
+ // If so, we haven't disallowed intercepting touch events yet.
+ // Make sure that we do so in case we're in a parent that can intercept.
+ if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
+ Math.abs(rawDeltaY) > mTouchSlop) {
+ final ViewParent parent = getParent();
+ if (parent != null) {
+ parent.requestDisallowInterceptTouchEvent(true);
+ }
+ }
+
+ final int motionIndex;
+ if (mMotionPosition >= 0) {
+ motionIndex = mMotionPosition - mFirstPosition;
+ } else {
+ // If we don't have a motion position that we can reliably track,
+ // pick something in the middle to make a best guess at things below.
+ motionIndex = getChildCount() / 2;
+ }
+
+ int motionViewPrevTop = 0;
+ View motionView = this.getChildAt(motionIndex);
+ if (motionView != null) {
+ motionViewPrevTop = motionView.getTop();
+ }
+
+ // No need to do all this work if we're not going to move anyway
+ boolean atEdge = false;
+ if (incrementalDeltaY != 0) {
+ atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
+ }
+
+ // Check to see if we have bumped into the scroll limit
+ motionView = this.getChildAt(motionIndex);
+ if (motionView != null) {
+ // Check if the top of the motion view is where it is
+ // supposed to be
+ final int motionViewRealTop = motionView.getTop();
+ if (atEdge) {
+ // Apply overscroll
+
+ int overscroll = -incrementalDeltaY -
+ (motionViewRealTop - motionViewPrevTop);
+ overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
+ 0, mOverscrollDistance, true);
+ if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
+ // Don't allow overfling if we're at the edge.
+ if (mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ }
+
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
+ !contentFits())) {
+ mDirection = 0; // Reset when entering overscroll.
+ mTouchMode = TOUCH_MODE_OVERSCROLL;
+ if (rawDeltaY > 0) {
+ mEdgeGlowTop.onPull((float) overscroll / getHeight());
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
+ } else if (rawDeltaY < 0) {
+ mEdgeGlowBottom.onPull((float) overscroll / getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
+ }
+ }
+ }
+ mMotionY = y;
+ invalidate();
+ }
+ mLastY = y;
+ }
+ } else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
+ if (y != mLastY) {
+ final int oldScroll = mScrollY;
+ final int newScroll = oldScroll - incrementalDeltaY;
+ int newDirection = y > mLastY ? 1 : -1;
+
+ if (mDirection == 0) {
+ mDirection = newDirection;
+ }
+
+ int overScrollDistance = -incrementalDeltaY;
+ if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
+ overScrollDistance = -oldScroll;
+ incrementalDeltaY += overScrollDistance;
+ } else {
+ incrementalDeltaY = 0;
+ }
+
+ if (overScrollDistance != 0) {
+ overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
+ 0, mOverscrollDistance, true);
+ final int overscrollMode = getOverScrollMode();
+ if (overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
+ !contentFits())) {
+ if (rawDeltaY > 0) {
+ mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
+ } else if (rawDeltaY < 0) {
+ mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
+ }
+ invalidate();
+ }
+ }
+
+ if (incrementalDeltaY != 0) {
+ // Coming back to 'real' list scrolling
+ mScrollY = 0;
+ invalidateParentIfNeeded();
+
+ // No need to do all this work if we're not going to move anyway
+ if (incrementalDeltaY != 0) {
+ trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
+ }
+
+ mTouchMode = TOUCH_MODE_SCROLL;
+
+ // We did not scroll the full amount. Treat this essentially like the
+ // start of a new touch scroll
+ final int motionPosition = findClosestMotionRow(y);
+
+ mMotionCorrection = 0;
+ View motionView = getChildAt(motionPosition - mFirstPosition);
+ mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
+ mMotionY = y;
+ mMotionPosition = motionPosition;
+ }
+ mLastY = y;
+ mDirection = newDirection;
+ }
+ }
+ }
+
public void onTouchModeChanged(boolean isInTouchMode) {
if (isInTouchMode) {
// Get rid of the selection when we enter touch mode
@@ -2856,7 +3024,6 @@
final int action = ev.getAction();
View v;
- int deltaY;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
@@ -2935,183 +3102,19 @@
mActivePointerId = ev.getPointerId(pointerIndex);
}
final int y = (int) ev.getY(pointerIndex);
- deltaY = y - mMotionY;
switch (mTouchMode) {
case TOUCH_MODE_DOWN:
case TOUCH_MODE_TAP:
case TOUCH_MODE_DONE_WAITING:
// Check if we have moved far enough that it looks more like a
// scroll than a tap
- startScrollIfNeeded(deltaY);
+ startScrollIfNeeded(y);
break;
case TOUCH_MODE_SCROLL:
- if (PROFILE_SCROLLING) {
- if (!mScrollProfilingStarted) {
- Debug.startMethodTracing("AbsListViewScroll");
- mScrollProfilingStarted = true;
- }
- }
-
- if (mScrollStrictSpan == null) {
- // If it's non-null, we're already in a scroll.
- mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
- }
-
- if (y != mLastY) {
- // We may be here after stopping a fling and continuing to scroll.
- // If so, we haven't disallowed intercepting touch events yet.
- // Make sure that we do so in case we're in a parent that can intercept.
- if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
- Math.abs(deltaY) > mTouchSlop) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
-
- final int rawDeltaY = deltaY;
- deltaY -= mMotionCorrection;
- int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
-
- final int motionIndex;
- if (mMotionPosition >= 0) {
- motionIndex = mMotionPosition - mFirstPosition;
- } else {
- // If we don't have a motion position that we can reliably track,
- // pick something in the middle to make a best guess at things below.
- motionIndex = getChildCount() / 2;
- }
-
- int motionViewPrevTop = 0;
- View motionView = this.getChildAt(motionIndex);
- if (motionView != null) {
- motionViewPrevTop = motionView.getTop();
- }
-
- // No need to do all this work if we're not going to move anyway
- boolean atEdge = false;
- if (incrementalDeltaY != 0) {
- atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
- }
-
- // Check to see if we have bumped into the scroll limit
- motionView = this.getChildAt(motionIndex);
- if (motionView != null) {
- // Check if the top of the motion view is where it is
- // supposed to be
- final int motionViewRealTop = motionView.getTop();
- if (atEdge) {
- // Apply overscroll
-
- int overscroll = -incrementalDeltaY -
- (motionViewRealTop - motionViewPrevTop);
- overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
- 0, mOverscrollDistance, true);
- if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
- // Don't allow overfling if we're at the edge.
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
-
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
- !contentFits())) {
- mDirection = 0; // Reset when entering overscroll.
- mTouchMode = TOUCH_MODE_OVERSCROLL;
- if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overscroll / getHeight());
- if (!mEdgeGlowBottom.isFinished()) {
- mEdgeGlowBottom.onRelease();
- }
- } else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overscroll / getHeight());
- if (!mEdgeGlowTop.isFinished()) {
- mEdgeGlowTop.onRelease();
- }
- }
- }
- }
- mMotionY = y;
- invalidate();
- }
- mLastY = y;
- }
- break;
-
case TOUCH_MODE_OVERSCROLL:
- if (y != mLastY) {
- final int rawDeltaY = deltaY;
- deltaY -= mMotionCorrection;
- int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
-
- final int oldScroll = mScrollY;
- final int newScroll = oldScroll - incrementalDeltaY;
- int newDirection = y > mLastY ? 1 : -1;
-
- if (mDirection == 0) {
- mDirection = newDirection;
- }
-
- int overScrollDistance = -incrementalDeltaY;
- if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
- overScrollDistance = -oldScroll;
- incrementalDeltaY += overScrollDistance;
- } else {
- incrementalDeltaY = 0;
- }
-
- if (overScrollDistance != 0) {
- overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
- 0, mOverscrollDistance, true);
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
- !contentFits())) {
- if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
- if (!mEdgeGlowBottom.isFinished()) {
- mEdgeGlowBottom.onRelease();
- }
- } else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
- if (!mEdgeGlowTop.isFinished()) {
- mEdgeGlowTop.onRelease();
- }
- }
- invalidate();
- }
- }
-
- if (incrementalDeltaY != 0) {
- // Coming back to 'real' list scrolling
- mScrollY = 0;
- invalidateParentIfNeeded();
-
- // No need to do all this work if we're not going to move anyway
- if (incrementalDeltaY != 0) {
- trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
- }
-
- mTouchMode = TOUCH_MODE_SCROLL;
-
- // We did not scroll the full amount. Treat this essentially like the
- // start of a new touch scroll
- final int motionPosition = findClosestMotionRow(y);
-
- mMotionCorrection = 0;
- View motionView = getChildAt(motionPosition - mFirstPosition);
- mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
- mMotionY = y;
- mMotionPosition = motionPosition;
- }
- mLastY = y;
- mDirection = newDirection;
- }
+ scrollIfNeeded(y);
break;
}
-
break;
}
@@ -3542,7 +3545,7 @@
final int y = (int) ev.getY(pointerIndex);
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
- if (startScrollIfNeeded(y - mMotionY)) {
+ if (startScrollIfNeeded(y)) {
return true;
}
break;
@@ -3769,6 +3772,10 @@
}
// Fall through
case TOUCH_MODE_FLING: {
+ if (mDataChanged) {
+ layoutChildren();
+ }
+
if (mItemCount == 0 || getChildCount() == 0) {
endFling();
return;
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 2d10bbe..72db8e8 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -896,6 +896,7 @@
@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
// We send selection events only from AdapterView to avoid
// generation of such event for each child.
getSelectedView().dispatchPopulateAccessibilityEvent(event);
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 7598e54..0a54743 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -26,6 +26,7 @@
import android.view.Gravity;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
/**
@@ -231,4 +232,10 @@
event.getText().add(mContext.getString(R.string.radiobutton_not_selected));
}
}
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setChecked(mChecked);
+ }
}
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index a7a05be..9ce8fe0 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -16,14 +16,10 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.FocusFinder;
import android.view.InputDevice;
@@ -569,16 +565,18 @@
final int oldX = mScrollX;
final int oldY = mScrollY;
final int range = getScrollRange();
- if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
+ final int overscrollMode = getOverScrollMode();
+ final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+ if (canOverscroll && overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
mOverscrollDistance, 0, true)) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ if (canOverscroll) {
final int pulledToX = oldX + deltaX;
if (pulledToX < 0) {
mEdgeGlowLeft.onPull((float) deltaX / getWidth());
@@ -604,11 +602,15 @@
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
- if (getChildCount() > 0) {
+ final int right = getScrollRange();
+ final int overscrollMode = getOverScrollMode();
+ final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && right > 0);
+
+ if (getChildCount() > 0 && canOverscroll) {
if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
fling(-initialVelocity);
} else {
- final int right = getScrollRange();
if (mScroller.springBack(mScrollX, mScrollY, 0, right, 0, 0)) {
invalidate();
}
@@ -1187,14 +1189,16 @@
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
- overScrollBy(x - oldX, y - oldY, oldX, oldY, getScrollRange(), 0,
+ final int range = getScrollRange();
+ final int overscrollMode = getOverScrollMode();
+ final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+ overScrollBy(x - oldX, y - oldY, oldX, oldY, range, 0,
mOverflingDistance, 0, false);
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int range = getScrollRange();
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ if (canOverscroll) {
if (x < 0 && oldX >= 0) {
mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
} else if (x > range && oldX <= range) {
@@ -1202,6 +1206,7 @@
}
}
}
+
awakenScrollBars();
// Keep on drawing until the animation has finished.
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b92130d..a5d6c9a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -212,6 +212,7 @@
@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
CharSequence contentDescription = getContentDescription();
if (!TextUtils.isEmpty(contentDescription)) {
event.getText().add(contentDescription);
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index a2910af..5c97593 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -988,7 +988,6 @@
mDropDownList.setSelector(mDropDownListHighlight);
}
mDropDownList.setAdapter(mAdapter);
- mDropDownList.setVerticalFadingEdgeEnabled(true);
mDropDownList.setOnItemClickListener(mItemClickListener);
mDropDownList.setFocusable(true);
mDropDownList.setFocusableInTouchMode(true);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5a97317..e37ccf8 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -264,7 +264,7 @@
// in the case of re-adding a header view, or adding one later on,
// we need to notify the observer
- if (mDataSetObserver != null) {
+ if (mAdapter != null && mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
@@ -299,7 +299,7 @@
public boolean removeHeaderView(View v) {
if (mHeaderViewInfos.size() > 0) {
boolean result = false;
- if (((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
+ if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
@@ -350,7 +350,7 @@
// in the case of re-adding a footer view, or adding one later on,
// we need to notify the observer
- if (mDataSetObserver != null) {
+ if (mAdapter != null && mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
@@ -384,7 +384,7 @@
public boolean removeFooterView(View v) {
if (mFooterViewInfos.size() > 0) {
boolean result = false;
- if (((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
+ if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 6a6bc23..d91eeb2 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -19,11 +19,9 @@
import com.android.internal.R;
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.StrictMode;
import android.util.AttributeSet;
import android.view.FocusFinder;
@@ -581,16 +579,18 @@
final int oldX = mScrollX;
final int oldY = mScrollY;
final int range = getScrollRange();
- if (overScrollBy(0, deltaY, 0, mScrollY, 0, range,
- 0, mOverscrollDistance, true)) {
+ final int overscrollMode = getOverScrollMode();
+ final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+ if (canOverscroll && overScrollBy(0, deltaY, 0, mScrollY,
+ 0, range, 0, mOverscrollDistance, true)) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ if (canOverscroll) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
mEdgeGlowTop.onPull((float) deltaY / getHeight());
@@ -616,11 +616,15 @@
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
- if (getChildCount() > 0) {
+ final int bottom = getScrollRange();
+ final int overscrollMode = getOverScrollMode();
+ final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && bottom > 0);
+
+ if (getChildCount() > 0 && canOverscroll) {
if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
fling(-initialVelocity);
} else {
- final int bottom = getScrollRange();
if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, bottom)) {
invalidate();
}
@@ -1193,14 +1197,16 @@
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
- overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, getScrollRange(),
+ final int range = getScrollRange();
+ final int overscrollMode = getOverScrollMode();
+ final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+ overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range,
0, mOverflingDistance, false);
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- final int range = getScrollRange();
- final int overscrollMode = getOverScrollMode();
- if (overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+ if (canOverscroll) {
if (y < 0 && oldY >= 0) {
mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
} else if (y > range && oldY <= range) {
@@ -1208,6 +1214,7 @@
}
}
}
+
awakenScrollBars();
// Keep on drawing until the animation has finished.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 191c4ca..80bfe99 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -489,6 +489,7 @@
public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
// this class fires events only when tabs are focused or selected
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
+ event.recycle();
return;
}
super.sendAccessibilityEventUnchecked(event);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b948114..edb1bfc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -461,10 +461,6 @@
mMovement = getDefaultMovementMethod();
mTransformation = null;
- TypedArray a =
- context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
-
int textColorHighlight = 0;
ColorStateList textColor = null;
ColorStateList textColorHint = null;
@@ -474,18 +470,23 @@
int styleIndex = -1;
boolean allCaps = false;
+ final Resources.Theme theme = context.getTheme();
+
/*
* Look the appearance up without checking first if it exists because
* almost every TextView has one and it greatly simplifies the logic
* to be able to parse the appearance first and then let specific tags
* for this View override it.
*/
+ TypedArray a = theme.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
TypedArray appearance = null;
- int ap = a.getResourceId(com.android.internal.R.styleable.TextView_textAppearance, -1);
+ int ap = a.getResourceId(
+ com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
+ a.recycle();
if (ap != -1) {
- appearance = context.obtainStyledAttributes(ap,
- com.android.internal.R.styleable.
- TextAppearance);
+ appearance = theme.obtainStyledAttributes(
+ ap, com.android.internal.R.styleable.TextAppearance);
}
if (appearance != null) {
int n = appearance.getIndexCount();
@@ -552,6 +553,9 @@
boolean password = false;
int inputType = EditorInfo.TYPE_NULL;
+ a = theme.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
+
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
@@ -3102,6 +3106,11 @@
text = "";
}
+ // If suggestions are not enabled, remove the suggestion spans from the text
+ if (!isSuggestionsEnabled()) {
+ text = removeSuggestionSpans(text);
+ }
+
if (!mUserSetTextScaleX) mTextPaint.setTextScaleX(1.0f);
if (text instanceof Spanned &&
@@ -3503,6 +3512,10 @@
applySingleLine(singleLine, !isPassword, true);
}
+ if (!isSuggestionsEnabled()) {
+ mText = removeSuggestionSpans(mText);
+ }
+
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
}
@@ -9547,6 +9560,9 @@
private int mNumberOfSuggestions;
private boolean mCursorWasVisibleBeforeSuggestions;
private SuggestionAdapter mSuggestionsAdapter;
+ private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
+ private final HashMap<SuggestionSpan, Integer> mSpansLengths;
+
private class CustomPopupWindow extends PopupWindow {
public CustomPopupWindow(Context context, int defStyle) {
@@ -9572,6 +9588,8 @@
public SuggestionsPopupWindow() {
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+ mSuggestionSpanComparator = new SuggestionSpanComparator();
+ mSpansLengths = new HashMap<SuggestionSpan, Integer>();
}
@Override
@@ -9599,10 +9617,9 @@
}
private class SuggestionInfo {
- int suggestionStart, suggestionEnd; // range of suggestion item with replacement text
- int spanStart, spanEnd; // range in TextView where text should be inserted
+ int suggestionStart, suggestionEnd; // range of actual suggestion within text
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
- int suggestionIndex; // the index of the suggestion inside suggestionSpan
+ int suggestionIndex; // the index of this suggestion inside suggestionSpan
SpannableStringBuilder text = new SpannableStringBuilder();
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext,
android.R.style.TextAppearance_SuggestionHighlight);
@@ -9650,6 +9667,26 @@
}
}
+ private class SuggestionSpanComparator implements Comparator<SuggestionSpan> {
+ public int compare(SuggestionSpan span1, SuggestionSpan span2) {
+ final int flag1 = span1.getFlags();
+ final int flag2 = span2.getFlags();
+ if (flag1 != flag2) {
+ // The order here should match what is used in updateDrawState
+ final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+ final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+ final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+ final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+ if (easy1 && !misspelled1) return -1;
+ if (easy2 && !misspelled2) return 1;
+ if (misspelled1) return -1;
+ if (misspelled2) return 1;
+ }
+
+ return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
+ }
+ }
+
/**
* Returns the suggestion spans that cover the current cursor position. The suggestion
* spans are sorted according to the length of text that they are attached to.
@@ -9659,24 +9696,16 @@
Spannable spannable = (Spannable) TextView.this.mText;
SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
- // Cache the span length for performance reason.
- final HashMap<SuggestionSpan, Integer> spansLengths =
- new HashMap<SuggestionSpan, Integer>();
-
+ mSpansLengths.clear();
for (SuggestionSpan suggestionSpan : suggestionSpans) {
int start = spannable.getSpanStart(suggestionSpan);
int end = spannable.getSpanEnd(suggestionSpan);
- spansLengths.put(suggestionSpan, Integer.valueOf(end - start));
+ mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
}
- // The suggestions are sorted according to the lenght of the text that they cover
- // (shorter first)
- Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() {
- public int compare(SuggestionSpan span1, SuggestionSpan span2) {
- return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue();
- }
- });
-
+ // The suggestions are sorted according to their types (easy correction first, then
+ // misspelled) and to the length of the text that they cover (shorter first).
+ Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
return suggestionSpans;
}
@@ -9774,8 +9803,6 @@
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
- suggestionInfo.spanStart = spanStart;
- suggestionInfo.spanEnd = spanEnd;
suggestionInfo.suggestionSpan = suggestionSpan;
suggestionInfo.suggestionIndex = suggestionIndex;
suggestionInfo.text.replace(0, suggestionInfo.text.length(),
@@ -9799,8 +9826,6 @@
final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
- suggestionInfo.spanStart = misspelledStart;
- suggestionInfo.spanEnd = misspelledEnd;
suggestionInfo.suggestionSpan = misspelledSpan;
suggestionInfo.suggestionIndex = -1;
suggestionInfo.text.replace(0, suggestionInfo.text.length(),
@@ -9832,8 +9857,9 @@
private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
int unionEnd) {
- final int spanStart = suggestionInfo.spanStart;
- final int spanEnd = suggestionInfo.spanEnd;
+ final Spannable text = (Spannable) mText;
+ final int spanStart = text.getSpanStart(suggestionInfo.suggestionSpan);
+ final int spanEnd = text.getSpanEnd(suggestionInfo.suggestionSpan);
// Adjust the start/end of the suggestion span
suggestionInfo.suggestionStart = spanStart - unionStart;
@@ -9853,10 +9879,11 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
+ Editable editable = (Editable) mText;
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
- final int spanStart = suggestionInfo.spanStart;
- final int spanEnd = suggestionInfo.spanEnd;
+ final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
+ final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
final String originalText = mText.subSequence(spanStart, spanEnd).toString();
if (suggestionInfo.suggestionIndex < 0) {
@@ -9867,7 +9894,6 @@
suggestionInfo.removeMisspelledFlag();
} else {
// SuggestionSpans are removed by replace: save them before
- Editable editable = (Editable) mText;
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
SuggestionSpan.class);
final int length = suggestionSpans.length;
@@ -9923,9 +9949,28 @@
}
}
- void showSuggestions() {
- if (!isSuggestionsEnabled() || !isTextEditable()) return;
+ /**
+ * Removes the suggestion spans.
+ */
+ CharSequence removeSuggestionSpans(CharSequence text) {
+ if (text instanceof Spanned) {
+ Spannable spannable;
+ if (text instanceof Spannable) {
+ spannable = (Spannable) text;
+ } else {
+ spannable = new SpannableString(text);
+ text = spannable;
+ }
+ SuggestionSpan[] spans = spannable.getSpans(0, text.length(), SuggestionSpan.class);
+ for (int i = 0; i < spans.length; i++) {
+ spannable.removeSpan(spans[i]);
+ }
+ }
+ return text;
+ }
+
+ void showSuggestions() {
if (mSuggestionsPopupWindow == null) {
mSuggestionsPopupWindow = new SuggestionsPopupWindow();
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index e6538b0..0141427 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -62,6 +62,7 @@
public ListMenuPresenter(Context context, int itemLayoutRes) {
this(itemLayoutRes, 0);
mContext = context;
+ mInflater = LayoutInflater.from(mContext);
}
/**
@@ -78,10 +79,13 @@
public void initForMenu(Context context, MenuBuilder menu) {
if (mThemeRes != 0) {
mContext = new ContextThemeWrapper(context, mThemeRes);
+ mInflater = LayoutInflater.from(mContext);
} else if (mContext != null) {
mContext = context;
+ if (mInflater == null) {
+ mInflater = LayoutInflater.from(mContext);
+ }
}
- mInflater = LayoutInflater.from(mContext);
mMenu = menu;
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 7434df3a..bbecb6c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -268,8 +268,10 @@
if (mTabScrollView != null && mIncludeTabs) {
ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
- lp.width = LayoutParams.WRAP_CONTENT;
- lp.height = LayoutParams.MATCH_PARENT;
+ if (lp != null) {
+ lp.width = LayoutParams.WRAP_CONTENT;
+ lp.height = LayoutParams.MATCH_PARENT;
+ }
mTabScrollView.setAllowCollapse(true);
}
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 423eff4..7d222f6 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -366,26 +366,22 @@
NPE_CHECK_RETURN_ZERO(env, jpaint);
NPE_CHECK_RETURN_ZERO(env, text);
+ size_t textLength = env->GetStringLength(text);
int count = end - start;
- if ((start | count) < 0) {
+ if ((start | count) < 0 || (size_t)end > textLength) {
doThrowAIOOBE(env);
return 0;
}
if (count == 0) {
return 0;
}
- size_t textLength = env->GetStringLength(text);
- if ((size_t)count > textLength) {
- doThrowAIOOBE(env);
- return 0;
- }
const jchar* textArray = env->GetStringChars(text, NULL);
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
#if RTL_USE_HARFBUZZ
- TextLayout::getTextRunAdvances(paint, textArray, start, count, end,
+ TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
paint->getFlags(), NULL /* dont need all advances */, width);
#else
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 7f79277..d04e059 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -163,20 +163,20 @@
// Update timing information for statistics
value->setElapsedTime(endTime - startTime);
- LOGD("CACHE MISS: Added entry for text='%s' with start=%d, count=%d, "
+ LOGD("CACHE MISS: Added entry with start=%d, count=%d, "
"contextCount=%d, entry size %d bytes, remaining space %d bytes"
- " - Compute time in nanos: %d",
- String8(text, contextCount).string(), start, count, contextCount,
- size, mMaxSize - mSize, value->getElapsedTime());
+ " - Compute time in nanos: %d - Text='%s' ",
+ start, count, contextCount, size, mMaxSize - mSize, value->getElapsedTime(),
+ String8(text, contextCount).string());
}
} else {
if (mDebugEnabled) {
LOGD("CACHE MISS: Calculated but not storing entry because it is too big "
- "for text='%s' with start=%d, count=%d, contextCount=%d, "
+ "with start=%d, count=%d, contextCount=%d, "
"entry size %d bytes, remaining space %d bytes"
- " - Compute time in nanos: %lld",
- String8(text, contextCount).string(), start, count, contextCount,
- size, mMaxSize - mSize, endTime);
+ " - Compute time in nanos: %lld - Text='%s'",
+ start, count, contextCount, size, mMaxSize - mSize, endTime,
+ String8(text, contextCount).string());
}
value.clear();
}
@@ -190,12 +190,12 @@
if (value->getElapsedTime() > 0) {
float deltaPercent = 100 * ((value->getElapsedTime() - elapsedTimeThruCacheGet)
/ ((float)value->getElapsedTime()));
- LOGD("CACHE HIT #%d for text='%s' with start=%d, count=%d, contextCount=%d "
+ LOGD("CACHE HIT #%d with start=%d, count=%d, contextCount=%d "
"- Compute time in nanos: %d - "
- "Cache get time in nanos: %lld - Gain in percent: %2.2f",
- mCacheHitCount, String8(text, contextCount).string(), start, count,
- contextCount,
- value->getElapsedTime(), elapsedTimeThruCacheGet, deltaPercent);
+ "Cache get time in nanos: %lld - Gain in percent: %2.2f - Text='%s' ",
+ mCacheHitCount, start, count, contextCount,
+ value->getElapsedTime(), elapsedTimeThruCacheGet, deltaPercent,
+ String8(text, contextCount).string());
}
if (mCacheHitCount % DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL == 0) {
dumpCacheStats();
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 0335ce7..e8933fe 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1562,8 +1562,8 @@
LOG_AND_FREE_DBUS_ERROR(&err);
}
- LOGV("... Health Device Code = %d, result = %d", code, result);
jint code = *(int *) user;
+ LOGV("... Health Device Code = %d, result = %d", code, result);
env->CallVoidMethod(nat->me,
method_onHealthDeviceConnectionResult,
code,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72863a2..9f2eef5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -18,7 +18,7 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android" android:sharedUserId="android.uid.system"
+ package="android" coreApp="true" android:sharedUserId="android.uid.system"
android:sharedUserLabel="@string/android_system_label">
<!-- ================================================ -->
diff --git a/core/res/res/drawable-hdpi/sym_def_app_icon.png b/core/res/res/drawable-hdpi/sym_def_app_icon.png
index 075d908..c8a38ed 100644
--- a/core/res/res/drawable-hdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_def_app_icon.png b/core/res/res/drawable-mdpi/sym_def_app_icon.png
index 9777d11..b3e10f6 100644
--- a/core/res/res/drawable-mdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/unlock_default.png b/core/res/res/drawable-mdpi/unlock_default.png
deleted file mode 100644
index 0a441c0..0000000
--- a/core/res/res/drawable-mdpi/unlock_default.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/unlock_halo.png b/core/res/res/drawable-mdpi/unlock_halo.png
deleted file mode 100644
index 09b0526..0000000
--- a/core/res/res/drawable-mdpi/unlock_halo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/unlock_ring.png b/core/res/res/drawable-mdpi/unlock_ring.png
deleted file mode 100644
index 0363a8b..0000000
--- a/core/res/res/drawable-mdpi/unlock_ring.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/unlock_wave.png b/core/res/res/drawable-mdpi/unlock_wave.png
deleted file mode 100644
index 21bfa24..0000000
--- a/core/res/res/drawable-mdpi/unlock_wave.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/unlock_default.png b/core/res/res/drawable-sw600dp-hdpi/unlock_default.png
new file mode 100644
index 0000000..95b006d
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-hdpi/unlock_default.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/unlock_halo.png b/core/res/res/drawable-sw600dp-hdpi/unlock_halo.png
new file mode 100644
index 0000000..acccb28
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-hdpi/unlock_halo.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/unlock_ring.png b/core/res/res/drawable-sw600dp-hdpi/unlock_ring.png
new file mode 100644
index 0000000..27260dd
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-hdpi/unlock_ring.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/unlock_wave.png b/core/res/res/drawable-sw600dp-hdpi/unlock_wave.png
new file mode 100644
index 0000000..e6b17db
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-hdpi/unlock_wave.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/unlock_default.png b/core/res/res/drawable-sw600dp-mdpi/unlock_default.png
new file mode 100644
index 0000000..dd6f3c1
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-mdpi/unlock_default.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/unlock_halo.png b/core/res/res/drawable-sw600dp-mdpi/unlock_halo.png
new file mode 100644
index 0000000..c9ed4c7
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-mdpi/unlock_halo.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/unlock_ring.png b/core/res/res/drawable-sw600dp-mdpi/unlock_ring.png
new file mode 100644
index 0000000..d50de84
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-mdpi/unlock_ring.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/unlock_wave.png b/core/res/res/drawable-sw600dp-mdpi/unlock_wave.png
new file mode 100644
index 0000000..9e38499
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-mdpi/unlock_wave.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/unlock_default.png b/core/res/res/drawable-sw600dp-xhdpi/unlock_default.png
new file mode 100644
index 0000000..8eea0f0
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xhdpi/unlock_default.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/unlock_halo.png b/core/res/res/drawable-sw600dp-xhdpi/unlock_halo.png
new file mode 100644
index 0000000..5c504e8
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xhdpi/unlock_halo.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/unlock_ring.png b/core/res/res/drawable-sw600dp-xhdpi/unlock_ring.png
new file mode 100644
index 0000000..7f698fd
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xhdpi/unlock_ring.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/unlock_wave.png b/core/res/res/drawable-sw600dp-xhdpi/unlock_wave.png
new file mode 100644
index 0000000..a11c956
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xhdpi/unlock_wave.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/sym_def_app_icon.png b/core/res/res/drawable-xhdpi/sym_def_app_icon.png
index f360399..f381f86 100644
--- a/core/res/res/drawable-xhdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-xhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 93bd76b..680eca7 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -26,8 +26,8 @@
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
+ android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:layout_marginRight="?android:attr/listPreferredItemPaddingRight"
android:duplicateParentState="true">
<TextView
diff --git a/core/res/res/mipmap-hdpi/sym_def_app_icon.png b/core/res/res/mipmap-hdpi/sym_def_app_icon.png
index 075d908..c8a38ed 100644
--- a/core/res/res/mipmap-hdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-mdpi/sym_def_app_icon.png b/core/res/res/mipmap-mdpi/sym_def_app_icon.png
index 9777d11..b3e10f6 100644
--- a/core/res/res/mipmap-mdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-xhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..f381f86
--- /dev/null
+++ b/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fc84f53..c990125 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3177,6 +3177,10 @@
<!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
<attr name="textAllCaps" />
</declare-styleable>
+ <declare-styleable name="TextViewAppearance">
+ <!-- Base text color, typeface, size, and style. -->
+ <attr name="textAppearance" />
+ </declare-styleable>
<declare-styleable name="SuggestionSpan">
<attr name="textUnderlineColor" />
<attr name="textUnderlineThickness" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 051ed14..1e5358e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -385,6 +385,9 @@
<!-- Default value for LED on time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOn">125</integer>
+ <!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
+ <bool name="config_intrusiveNotificationLed">false</bool>
+
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
@@ -423,6 +426,10 @@
<integer-array name="config_autoBrightnessLevels">
</integer-array>
+
+ <!-- Minimum screen brightness allowed by the power manager. -->
+ <integer name="config_screenBrightnessDim">20</integer>
+
<!-- Array of output values for LCD backlight corresponding to the LUX values
in the config_autoBrightnessLevels array. This array should have size one greater
than the size of the config_autoBrightnessLevels array.
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index c8f7fb8..3378dc8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -616,6 +616,9 @@
<item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
<item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
<item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
+
+ <item name="listPreferredItemPaddingLeft">10dip</item>
+ <item name="listPreferredItemPaddingRight">10dip</item>
</style>
<!-- Variation of Theme.Dialog that does not include a frame (or background).
@@ -640,6 +643,8 @@
<item name="windowTitleStyle">@android:style/DialogWindowTitle</item>
<item name="windowContentOverlay">@null</item>
<item name="itemTextAppearance">@android:style/TextAppearance.Large.Inverse</item>
+ <item name="textAppearanceListItem">@android:style/TextAppearance.Large.Inverse</item>
+ <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
</style>
<!-- Default dark theme for panel windows. This removes all extraneous
diff --git a/core/res/res/xml/apns.xml b/core/res/res/xml/apns.xml
index 2c69b40..8c7245c 100644
--- a/core/res/res/xml/apns.xml
+++ b/core/res/res/xml/apns.xml
@@ -17,10 +17,9 @@
*/
-->
-<!-- use empty string to specify no proxy or port -->
-<!-- If you edit this version, also edit the version in the partner-supplied
+<!-- If you edit this version, also edit the version in the partner-supplied
apns-conf.xml configuration file -->
-<apns version="6">
+<apns version="7">
</apns>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 146466f..cadc895 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -88,6 +88,7 @@
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
+ <uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
<!--os storage test permissions -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
diff --git a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
index 8922f27..cc8c4a6 100644
--- a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
+++ b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2011 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.content.pm;
import android.os.Parcel;
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 68ddcc4..9575ced 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -42,6 +42,7 @@
import android.provider.Settings.SettingNotFoundException;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -3121,6 +3122,14 @@
invokeInstallPackageFail(Uri.fromFile(invalidFile), 0, retCode);
}
+ @SmallTest
+ public void testGetVerifierDeviceIdentity() {
+ PackageManager pm = getPm();
+ VerifierDeviceIdentity id = pm.getVerifierDeviceIdentity();
+
+ assertNotNull("Verifier device identity should not be null", id);
+ }
+
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
new file mode 100644
index 0000000..e6a6a26
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2011 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.content.pm;
+
+import android.os.Parcel;
+
+import java.util.Random;
+
+public class VerifierDeviceIdentityTest extends android.test.AndroidTestCase {
+ private static final long TEST_1 = 0x7A5F00FF5A55AAA5L;
+
+ private static final String TEST_1_ENCODED = "HUXY-A75N-FLKV-F";
+
+ private static final long TEST_2 = 0x5A05FF5A05F0A555L;
+
+ private static final long TEST_MAXVALUE = Long.MAX_VALUE;
+
+ private static final String TEST_MAXVALUE_ENCODED = "H777-7777-7777-7";
+
+ private static final long TEST_MINVALUE = Long.MIN_VALUE;
+
+ private static final String TEST_MINVALUE_ENCODED = "IAAA-AAAA-AAAA-A";
+
+ private static final long TEST_ZERO = 0L;
+
+ private static final String TEST_ZERO_ENCODED = "AAAA-AAAA-AAAA-A";
+
+ private static final long TEST_NEGONE = -1L;
+
+ private static final String TEST_NEGONE_ENCODED = "P777-7777-7777-7";
+
+ private static final String TEST_OVERFLOW_ENCODED = "QAAA-AAAA-AAAA-A";
+
+ public void testVerifierDeviceIdentity_Equals_Success() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+ VerifierDeviceIdentity id2 = new VerifierDeviceIdentity(TEST_1);
+
+ assertTrue("The two VerifierDeviceIdentity instances should be equal", id1.equals(id2));
+ }
+
+ public void testVerifierDeviceIdentity_Equals_Failure() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+ VerifierDeviceIdentity id2 = new VerifierDeviceIdentity(TEST_2);
+
+ assertFalse("The two VerifierDeviceIdentity instances should be unique", id1.equals(id2));
+ }
+
+ public void testVerifierDeviceIdentity_HashCode() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+
+ assertEquals("The VerifierDeviceIdentity should have the same hashcode as its identity",
+ (int) TEST_1, id1.hashCode());
+ }
+
+ public void testVerifierDeviceIdentity_ToString_Success() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+
+ assertEquals("The identity should encode correctly to the expected Base 32 string",
+ TEST_1_ENCODED, id1.toString());
+ }
+
+ public void testVerifierDeviceIdentity_ToString_Largest() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_MAXVALUE);
+
+ assertEquals("The identity should encode correctly to the expected Base 32 string",
+ TEST_MAXVALUE_ENCODED, id1.toString());
+ }
+
+ public void testVerifierDeviceIdentity_ToString_Zero() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_ZERO);
+
+ assertEquals("The identity should encode correctly to the expected Base 32 string",
+ TEST_ZERO_ENCODED, id1.toString());
+ }
+
+ public void testVerifierDeviceIdentity_ToString_NegOne() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_NEGONE);
+
+ assertEquals("The identity should encode correctly to the expected Base 32 string",
+ TEST_NEGONE_ENCODED, id1.toString());
+ }
+
+ public void testVerifierDeviceIdentity_ToString_MinValue() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_MINVALUE);
+
+ assertEquals("The identity should encode correctly to the expected Base 32 string",
+ TEST_MINVALUE_ENCODED, id1.toString());
+ }
+
+ public void testVerifierDeviceIdentity_Parcel_ReadNegative() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_MINVALUE);
+
+ Parcel parcel = Parcel.obtain();
+ parcel.writeLong(TEST_MINVALUE);
+ parcel.setDataPosition(0);
+
+ VerifierDeviceIdentity id2 = VerifierDeviceIdentity.CREATOR.createFromParcel(parcel);
+
+ assertEquals("Parcel created should match expected value", id1, id2);
+ }
+
+ public void testVerifierDeviceIdentity_Parcel_Read_Pass() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+
+ Parcel parcel = Parcel.obtain();
+ id1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ VerifierDeviceIdentity id2 = VerifierDeviceIdentity.CREATOR.createFromParcel(parcel);
+
+ assertEquals("Original identity and parceled identity should be the same", id1, id2);
+ }
+
+ private static class MockRandom extends Random {
+ private long mNextLong;
+
+ public MockRandom() {
+ }
+
+ public void setNextLong(long nextLong) {
+ mNextLong = nextLong;
+ }
+
+ @Override
+ public long nextLong() {
+ return mNextLong;
+ }
+ }
+
+ public void testVerifierDeviceIdentity_Generate_MinValue() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_MINVALUE);
+
+ MockRandom random = new MockRandom();
+ random.setNextLong(Long.MIN_VALUE);
+ VerifierDeviceIdentity id2 = VerifierDeviceIdentity.generate(random);
+
+ assertEquals("Identity created from Long.MIN_VALUE and one created from return from RNG"
+ + " should be the same", id1, id2);
+ }
+
+ public void testVerifierDeviceIdentity_Generate_Random() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+
+ MockRandom random = new MockRandom();
+ random.setNextLong(TEST_1);
+ VerifierDeviceIdentity id2 = VerifierDeviceIdentity.generate(random);
+
+ assertEquals("Identity should end up being same when coming from RNG", id1, id2);
+ }
+
+ public void testVerifierDeviceIdentity_Parse_Normal() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_1);
+
+ VerifierDeviceIdentity id2 = VerifierDeviceIdentity.parse(TEST_1_ENCODED);
+
+ assertEquals("Parsed device identity should have the same value as original identity",
+ id1, id2);
+ }
+
+ public void testVerifierDeviceIdentity_Parse_MaxValue() {
+ VerifierDeviceIdentity id1 = new VerifierDeviceIdentity(TEST_MAXVALUE);
+
+ VerifierDeviceIdentity id2 = VerifierDeviceIdentity.parse(TEST_MAXVALUE_ENCODED);
+
+ assertEquals("Original max value and parsed max value should be equal", id1, id2);
+ }
+
+ public void testVerifierDeviceIdentity_Parse_TooShort() {
+ try {
+ VerifierDeviceIdentity id = VerifierDeviceIdentity.parse("AAAA-AAAA-AAAA-");
+ fail("Parsing should fail when device identifier is too short");
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ }
+
+ public void testVerifierDeviceIdentity_Parse_WayTooShort() {
+ try {
+ VerifierDeviceIdentity id = VerifierDeviceIdentity.parse("----------------");
+ fail("Parsing should fail when device identifier is too short");
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ }
+
+ public void testVerifierDeviceIdentity_Parse_TooLong() {
+ try {
+ VerifierDeviceIdentity id = VerifierDeviceIdentity.parse("AAAA-AAAA-AAAA-AA");
+ fail("Parsing should fail when device identifier is too long");
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ }
+
+ public void testVerifierDeviceIdentity_Parse_Overflow() {
+ try {
+ VerifierDeviceIdentity id = VerifierDeviceIdentity.parse(TEST_OVERFLOW_ENCODED);
+ fail("Parsing should fail when the value will overflow");
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index b888d9a..e1db073 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -407,6 +407,54 @@
assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
}
+ public void testIndexBeforeAfter() throws Exception {
+ final long BUCKET_SIZE = HOUR_IN_MILLIS;
+ stats = new NetworkStatsHistory(BUCKET_SIZE);
+
+ final long FIRST_START = TEST_START;
+ final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
+ final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
+ final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
+ final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
+ final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
+
+ stats.recordData(FIRST_START, FIRST_END,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ stats.recordData(SECOND_START, SECOND_END,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ stats.recordData(THIRD_START, THIRD_END,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+
+ // should have buckets: 2+1+2
+ assertEquals(5, stats.size());
+
+ assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
+ assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
+ assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
+ assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
+ assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
+ assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
+ assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
+ assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
+ assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
+ }
+
+ private static void assertIndexBeforeAfter(
+ NetworkStatsHistory stats, int before, int after, long time) {
+ assertEquals("unexpected before", before, stats.getIndexBefore(time));
+ assertEquals("unexpected after", after, stats.getIndexAfter(time));
+ }
+
private static long performVarLong(long before) throws Exception {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
writeVarLong(new DataOutputStream(out), before);
diff --git a/docs/html/guide/developing/debugging/ddms.jd b/docs/html/guide/developing/debugging/ddms.jd
index 0d47ae5..4398ec9 100644
--- a/docs/html/guide/developing/debugging/ddms.jd
+++ b/docs/html/guide/developing/debugging/ddms.jd
@@ -60,9 +60,9 @@
<p>The following screenshot shows a typical DDMS screen in Eclipse. If you are starting DDMS from
the command line, the screen is slightly different, but much of the functionality is identical.
- Notice that the highlighted process, <code>com.example.android.notepad</code>, that is running in the emulator
- has the debugging port 8700 assigned to it as well as 8609. This signifies that DDMS is currently
- forwarding port 8609 to the static debugging port of 8700.</p>
+ Notice that the highlighted process, <code>com.android.email</code>, that is running in the emulator
+ has the debugging port 8700 assigned to it as well as 8606. This signifies that DDMS is currently
+ forwarding port 8606 to the static debugging port of 8700.</p>
<img src="{@docRoot}images/debug-ddms.png"
width="1024" />
@@ -76,7 +76,7 @@
<p class="note"><strong>Tip:</strong> You can set a number of DDMS preferences in
<strong>File</strong> > <strong>Preferences</strong>. Preferences are saved to
- <code>$HOME/.ddmsrc</code>.</p>
+ <code>$HOME/.android/ddms.cfg</code>.</p>
<p class="warning"><strong>Known debugging issues with Dalvik</strong><br />
Debugging an application in the Dalvik VM should work the same as it does in other VMs. However,
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index dd00224..4558800 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -27,7 +27,8 @@
<dt>can contain:</dt>
<dd><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
-<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code></dd>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission></a></code></dd>
<dt>description:</dt>
<dd>Declares a content provider — a subclass of
@@ -252,7 +253,7 @@
<dt><a name="sync"></a>{@code android:syncable}</dt>
<dd>Whether or not the data under the content provider's control
is to be synchronized with data on a server — "{@code true}"
-if it is to be synchronized, and "{@ code false}" if not.</dd>
+if it is to be synchronized, and "{@code false}" if not.</dd>
<dt><a name="wprmsn"></a>{@code android:writePermission}</dt>
<dd>A permission that clients must have to make changes to the data
diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd
index ffaec4c..3dfe55d 100644
--- a/docs/html/sdk/win-usb.jd
+++ b/docs/html/sdk/win-usb.jd
@@ -181,7 +181,7 @@
<li>Expand the <em>Third party Add-ons</em> and <em>Google Inc. add-ons</em>.</li>
<li>Check <strong>Google Usb Driver package</strong> and click <strong>Install selected</strong>.</li>
<li>Proceed to install the package. When done, the driver files are
-downloaded into the <code><sdk>\google-usb_driver\</code> directory.</li>
+downloaded into the <code><sdk>\extras\google\usb_driver\</code> directory.</li>
</ol>
@@ -229,7 +229,7 @@
<li>Select <strong>Browse my computer for driver software</strong> and click
<strong>Next</strong>.</li>
<li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\google-usb_driver\}.)</li>
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
<li>Click <strong>Next</strong> to install the driver.</li>
</ol>
@@ -252,7 +252,7 @@
<strong>Search removable media</strong>; and check <strong>Include this location in the
search</strong>.</li>
<li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\google-usb_driver\}.)</li>
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
<li>Click <strong>Next</strong> to upgrade the driver.</li>
</ol>
@@ -274,7 +274,7 @@
removable media</strong>; and check <strong>Include
this location in the search</strong>.</li>
<li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\google-usb_driver\}.)</li>
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
<li>Click <strong>Next</strong> to install the driver.</li>
</ol>
@@ -296,7 +296,7 @@
removable media</strong>; and check <strong>Include
this location in the search</strong>.</li>
<li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\google-usb_driver\}.)</li>
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li>
<li>Click <strong>Next</strong> to upgrade the driver.</li>
</ol>
@@ -314,8 +314,8 @@
<li>Select <strong>I don't have the disk. Show me other options</strong>.</li>
<li>Select <strong>Browse my computer for driver software</strong>.</li>
<li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\google-usb_driver\}.) As long as you specified the exact
-location of the
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the
+exact location of the
installation package, you may leave <strong>Include subfolders</strong> checked or
unchecked—it doesn't matter.</li>
<li>Click <strong>Next</strong>. Vista may prompt you to confirm the privilege elevation
@@ -339,7 +339,7 @@
search for the driver
software. Select <strong>Browse my computer for driver software</strong>.</li>
<li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
-Driver is located in {@code <sdk>\google-usb_driver\}.) As long as you specified the
+Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the
exact location of the
installation package, you may leave <strong>Include subfolders</strong> checked or
unchecked—it doesn't matter.</li>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index ee65223..ce42612 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -20,7 +20,6 @@
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
-import android.util.DisplayMetrics;
/**
* The Paint class holds the style and color information about how to draw
@@ -344,8 +343,10 @@
public Paint(int flags) {
mNativePaint = native_init();
setFlags(flags | DEFAULT_PAINT_FLAGS);
- setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
- ? HINTING_OFF : HINTING_ON);
+ // TODO: Turning off hinting has undesirable side effects, we need to
+ // revisit hinting once we add support for subpixel positioning
+ // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
+ // ? HINTING_OFF : HINTING_ON);
mCompatScaling = mInvCompatScaling = 1;
}
@@ -365,8 +366,10 @@
public void reset() {
native_reset(mNativePaint);
setFlags(DEFAULT_PAINT_FLAGS);
- setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
- ? HINTING_OFF : HINTING_ON);
+ // TODO: Turning off hinting has undesirable side effects, we need to
+ // revisit hinting once we add support for subpixel positioning
+ // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
+ // ? HINTING_OFF : HINTING_ON);
mHasCompatScaling = false;
mCompatScaling = mInvCompatScaling = 1;
mBidiFlags = BIDI_DEFAULT_LTR;
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 7c4e147..34f9070 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -79,7 +79,7 @@
float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
- canvas.rotate(mCurrentDegrees, px, py);
+ canvas.rotate(mCurrentDegrees, px + bounds.left, py + bounds.top);
drawable.draw(canvas);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 923518d..d1a8105 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -486,6 +486,7 @@
int mSessionId;
int mAuxEffectId;
Mutex mLock;
+ status_t mRestoreStatus;
};
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index e965f14..b7286e5 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -164,6 +164,8 @@
void sendFormatChange();
+ void signalError(OMX_ERRORTYPE error = OMX_ErrorUndefined);
+
DISALLOW_EVIL_CONSTRUCTORS(ACodec);
};
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 17dd931..2ebfe0a 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -73,27 +73,27 @@
}
-static void Update2DTexture(const Allocation *alloc, const void *ptr, uint32_t xoff, uint32_t yoff,
- uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h) {
+static void Update2DTexture(const Context *rsc, const Allocation *alloc, const void *ptr,
+ uint32_t xoff, uint32_t yoff, uint32_t lod,
+ RsAllocationCubemapFace face, uint32_t w, uint32_t h) {
DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
rsAssert(drv->textureID);
- glBindTexture(drv->glTarget, drv->textureID);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
+ RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
GLenum t = GL_TEXTURE_2D;
if (alloc->mHal.state.hasFaces) {
t = gFaceOrder[face];
}
- glTexSubImage2D(t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
+ RSD_CALL_GL(glTexSubImage2D, t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
}
static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) {
DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
- glBindTexture(drv->glTarget, drv->textureID);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
+ RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
uint32_t faceCount = 1;
if (alloc->mHal.state.hasFaces) {
@@ -112,12 +112,12 @@
}
if (isFirstUpload) {
- glTexImage2D(t, lod, drv->glFormat,
+ RSD_CALL_GL(glTexImage2D, t, lod, drv->glFormat,
alloc->mHal.state.type->getLODDimX(lod),
alloc->mHal.state.type->getLODDimY(lod),
0, drv->glFormat, drv->glType, p);
} else {
- glTexSubImage2D(t, lod, 0, 0,
+ RSD_CALL_GL(glTexSubImage2D, t, lod, 0, 0,
alloc->mHal.state.type->getLODDimX(lod),
alloc->mHal.state.type->getLODDimY(lod),
drv->glFormat, drv->glType, p);
@@ -126,7 +126,7 @@
}
if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
- glGenerateMipmap(drv->glTarget);
+ RSD_CALL_GL(glGenerateMipmap, drv->glTarget);
}
rsdGLCheckError(rsc, "Upload2DTexture");
}
@@ -145,7 +145,7 @@
bool isFirstUpload = false;
if (!drv->textureID) {
- glGenTextures(1, &drv->textureID);
+ RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
isFirstUpload = true;
}
@@ -168,7 +168,7 @@
}
if (!drv->renderTargetID) {
- glGenRenderbuffers(1, &drv->renderTargetID);
+ RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID);
if (!drv->renderTargetID) {
// This should generally not happen
@@ -176,8 +176,8 @@
rsc->dumpDebug();
return;
}
- glBindRenderbuffer(GL_RENDERBUFFER, drv->renderTargetID);
- glRenderbufferStorage(GL_RENDERBUFFER, drv->glFormat,
+ RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID);
+ RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat,
alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY);
}
rsdGLCheckError(rsc, "AllocateRenderTarget");
@@ -192,17 +192,17 @@
//alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
if (!drv->bufferID) {
- glGenBuffers(1, &drv->bufferID);
+ RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID);
}
if (!drv->bufferID) {
LOGE("Upload to buffer object failed");
drv->uploadDeferred = true;
return;
}
- glBindBuffer(drv->glTarget, drv->bufferID);
- glBufferData(drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
+ RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID);
+ RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
drv->mallocPtr, GL_DYNAMIC_DRAW);
- glBindBuffer(drv->glTarget, 0);
+ RSD_CALL_GL(glBindBuffer, drv->glTarget, 0);
rsdGLCheckError(rsc, "UploadToBufferObject");
}
@@ -261,11 +261,11 @@
//mBufferID = 0;
}
if (drv->textureID) {
- glDeleteTextures(1, &drv->textureID);
+ RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID);
drv->textureID = 0;
}
if (drv->renderTargetID) {
- glDeleteRenderbuffers(1, &drv->renderTargetID);
+ RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID);
drv->renderTargetID = 0;
}
@@ -323,7 +323,7 @@
drv->readBackFBO->setActive(rsc);
// Do the readback
- glReadPixels(0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
+ RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
drv->glFormat, drv->glType, alloc->getPtr());
// Revert framebuffer to its original
@@ -414,7 +414,7 @@
}
drv->uploadDeferred = true;
} else {
- Update2DTexture(alloc, data, xoff, yoff, lod, face, w, h);
+ Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h);
}
}
diff --git a/libs/rs/driver/rsdFrameBufferObj.cpp b/libs/rs/driver/rsdFrameBufferObj.cpp
index 145bf34..91452b0 100644
--- a/libs/rs/driver/rsdFrameBufferObj.cpp
+++ b/libs/rs/driver/rsdFrameBufferObj.cpp
@@ -17,6 +17,7 @@
#include "rsdFrameBufferObj.h"
#include "rsdAllocation.h"
+#include "rsdGL.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -124,9 +125,9 @@
bool framebuffer = renderToFramebuffer();
if (!framebuffer) {
if(mFBOId == 0) {
- glGenFramebuffers(1, &mFBOId);
+ RSD_CALL_GL(glGenFramebuffers, 1, &mFBOId);
}
- glBindFramebuffer(GL_FRAMEBUFFER, mFBOId);
+ RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, mFBOId);
if (mDirty) {
setDepthAttachment();
@@ -134,10 +135,10 @@
mDirty = false;
}
- glViewport(0, 0, mWidth, mHeight);
+ RSD_CALL_GL(glViewport, 0, 0, mWidth, mHeight);
checkError(rsc);
} else {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
+ RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, 0);
+ RSD_CALL_GL(glViewport, 0, 0, rsc->getWidth(), rsc->getHeight());
}
}
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 04446ad..c5b81db 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -135,18 +135,19 @@
LOGV("%p, deinitEGL", rsc);
if (dc->gl.egl.context != EGL_NO_CONTEXT) {
- eglMakeCurrent(dc->gl.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surfaceDefault);
+ RSD_CALL_GL(eglMakeCurrent, dc->gl.egl.display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surfaceDefault);
if (dc->gl.egl.surface != EGL_NO_SURFACE) {
- eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
+ RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surface);
}
- eglDestroyContext(dc->gl.egl.display, dc->gl.egl.context);
+ RSD_CALL_GL(eglDestroyContext, dc->gl.egl.display, dc->gl.egl.context);
checkEglError("eglDestroyContext");
}
gGLContextCount--;
if (!gGLContextCount) {
- eglTerminate(dc->gl.egl.display);
+ RSD_CALL_GL(eglTerminate, dc->gl.egl.display);
}
}
@@ -202,21 +203,25 @@
rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
LOGV("%p initEGL start", rsc);
+ rsc->setWatchdogGL("eglGetDisplay", __LINE__, __FILE__);
dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
checkEglError("eglGetDisplay");
- eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
+ RSD_CALL_GL(eglInitialize, dc->gl.egl.display,
+ &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
checkEglError("eglInitialize");
EGLBoolean ret;
EGLint numConfigs = -1, n = 0;
+ rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
checkEglError("eglGetConfigs", ret);
if (numConfigs) {
EGLConfig* const configs = new EGLConfig[numConfigs];
+ rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
ret = eglChooseConfig(dc->gl.egl.display,
configAttribs, configs, numConfigs, &n);
if (!ret || !n) {
@@ -261,32 +266,38 @@
}
//}
+ rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__);
dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
EGL_NO_CONTEXT, context_attribs2);
checkEglError("eglCreateContext");
if (dc->gl.egl.context == EGL_NO_CONTEXT) {
LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
+ rsc->setWatchdogGL(NULL, 0, NULL);
return false;
}
gGLContextCount++;
EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+ rsc->setWatchdogGL("eglCreatePbufferSurface", __LINE__, __FILE__);
dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config,
pbuffer_attribs);
checkEglError("eglCreatePbufferSurface");
if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE");
rsdGLShutdown(rsc);
+ rsc->setWatchdogGL(NULL, 0, NULL);
return false;
}
+ rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
dc->gl.egl.surfaceDefault, dc->gl.egl.context);
if (ret == EGL_FALSE) {
LOGE("eglMakeCurrent returned EGL_FALSE");
checkEglError("eglMakeCurrent", ret);
rsdGLShutdown(rsc);
+ rsc->setWatchdogGL(NULL, 0, NULL);
return false;
}
@@ -314,6 +325,7 @@
if (!verptr) {
LOGE("Error, OpenGL ES Lite not supported");
rsdGLShutdown(rsc);
+ rsc->setWatchdogGL(NULL, 0, NULL);
return false;
} else {
sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
@@ -352,6 +364,7 @@
dc->gl.currentFrameBuffer = NULL;
LOGV("initGLThread end %p", rsc);
+ rsc->setWatchdogGL(NULL, 0, NULL);
return true;
}
@@ -363,10 +376,12 @@
// WAR: Some drivers fail to handle 0 size surfaces correcntly.
// Use the pbuffer to avoid this pitfall.
if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) {
+ rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
dc->gl.egl.surfaceDefault, dc->gl.egl.context);
checkEglError("eglMakeCurrent", ret);
+ rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__);
ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
checkEglError("eglDestroySurface", ret);
@@ -385,6 +400,7 @@
dc->gl.width = w;
dc->gl.height = h;
+ rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
dc->gl.wndSurface, NULL);
checkEglError("eglCreateWindowSurface");
@@ -392,16 +408,18 @@
LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
}
+ rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
dc->gl.egl.surface, dc->gl.egl.context);
checkEglError("eglMakeCurrent", ret);
}
+ rsc->setWatchdogGL(NULL, 0, NULL);
return true;
}
void rsdGLSwap(const android::renderscript::Context *rsc) {
RsdHal *dc = (RsdHal *)rsc->mHal.drv;
- eglSwapBuffers(dc->gl.egl.display, dc->gl.egl.surface);
+ RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
}
void rsdGLCheckError(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 0d5b7e7..fc33885 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -20,6 +20,8 @@
#include <rs_hal.h>
#include <EGL/egl.h>
+#define RSD_CALL_GL(x, ...) rsc->setWatchdogGL(#x, __LINE__, __FILE__); x(__VA_ARGS__); rsc->setWatchdogGL(NULL, 0, NULL)
+
class RsdShaderCache;
class RsdVertexArrayState;
class RsdFrameBufferObj;
@@ -73,7 +75,6 @@
} RsdGL;
-
bool rsdGLInit(const android::renderscript::Context *rsc);
void rsdGLShutdown(const android::renderscript::Context *rsc);
bool rsdGLSetSurface(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index 4315c0d..019167b 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -130,7 +130,8 @@
return true;
}
-void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
+void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
+ uint32_t start, uint32_t len) const {
if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
LOGE("Invalid mesh or parameters");
return;
@@ -171,14 +172,16 @@
}
if (drvAlloc->bufferID) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID);
- glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+ RSD_CALL_GL(glBindBuffer, GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID);
+ RSD_CALL_GL(glDrawElements, mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT,
+ (uint16_t *)(start * 2));
} else {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, drvAlloc->mallocPtr);
+ RSD_CALL_GL(glBindBuffer, GL_ELEMENT_ARRAY_BUFFER, 0);
+ RSD_CALL_GL(glDrawElements, mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT,
+ drvAlloc->mallocPtr);
}
} else {
- glDrawArrays(mGLPrimitives[primIndex], start, len);
+ RSD_CALL_GL(glDrawArrays, mGLPrimitives[primIndex], start, len);
}
rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange");
diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp
index 65995be..b493759 100644
--- a/libs/rs/driver/rsdProgramRaster.cpp
+++ b/libs/rs/driver/rsdProgramRaster.cpp
@@ -32,18 +32,18 @@
return true;
}
-void rsdProgramRasterSetActive(const Context *, const ProgramRaster *pr) {
+void rsdProgramRasterSetActive(const Context *rsc, const ProgramRaster *pr) {
switch (pr->mHal.state.cull) {
case RS_CULL_BACK:
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
+ RSD_CALL_GL(glEnable, GL_CULL_FACE);
+ RSD_CALL_GL(glCullFace, GL_BACK);
break;
case RS_CULL_FRONT:
- glEnable(GL_CULL_FACE);
- glCullFace(GL_FRONT);
+ RSD_CALL_GL(glEnable, GL_CULL_FACE);
+ RSD_CALL_GL(glCullFace, GL_FRONT);
break;
case RS_CULL_NONE:
- glDisable(GL_CULL_FACE);
+ RSD_CALL_GL(glDisable, GL_CULL_FACE);
break;
}
diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp
index e591453..af44b02 100644
--- a/libs/rs/driver/rsdProgramStore.cpp
+++ b/libs/rs/driver/rsdProgramStore.cpp
@@ -156,29 +156,29 @@
void rsdProgramStoreSetActive(const Context *rsc, const ProgramStore *ps) {
DrvProgramStore *drv = (DrvProgramStore *)ps->mHal.drv;
- glColorMask(ps->mHal.state.colorRWriteEnable,
+ RSD_CALL_GL(glColorMask, ps->mHal.state.colorRWriteEnable,
ps->mHal.state.colorGWriteEnable,
ps->mHal.state.colorBWriteEnable,
ps->mHal.state.colorAWriteEnable);
if (drv->blendEnable) {
- glEnable(GL_BLEND);
- glBlendFunc(drv->blendSrc, drv->blendDst);
+ RSD_CALL_GL(glEnable, GL_BLEND);
+ RSD_CALL_GL(glBlendFunc, drv->blendSrc, drv->blendDst);
} else {
- glDisable(GL_BLEND);
+ RSD_CALL_GL(glDisable, GL_BLEND);
}
if (rsc->mUserSurfaceConfig.depthMin > 0) {
- glDepthMask(ps->mHal.state.depthWriteEnable);
+ RSD_CALL_GL(glDepthMask, ps->mHal.state.depthWriteEnable);
if (drv->depthTestEnable || ps->mHal.state.depthWriteEnable) {
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(drv->depthFunc);
+ RSD_CALL_GL(glEnable, GL_DEPTH_TEST);
+ RSD_CALL_GL(glDepthFunc, drv->depthFunc);
} else {
- glDisable(GL_DEPTH_TEST);
+ RSD_CALL_GL(glDisable, GL_DEPTH_TEST);
}
} else {
- glDepthMask(false);
- glDisable(GL_DEPTH_TEST);
+ RSD_CALL_GL(glDepthMask, false);
+ RSD_CALL_GL(glDisable, GL_DEPTH_TEST);
}
/*
@@ -190,9 +190,9 @@
*/
if (ps->mHal.state.ditherEnable) {
- glEnable(GL_DITHER);
+ RSD_CALL_GL(glEnable, GL_DITHER);
} else {
- glDisable(GL_DITHER);
+ RSD_CALL_GL(glDisable, GL_DITHER);
}
}
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index 90fe4b2..16ff063 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -178,22 +178,22 @@
if (mShaderID) {
const char * ss = mShader.string();
- glShaderSource(mShaderID, 1, &ss, NULL);
- glCompileShader(mShaderID);
+ RSD_CALL_GL(glShaderSource, mShaderID, 1, &ss, NULL);
+ RSD_CALL_GL(glCompileShader, mShaderID);
GLint compiled = 0;
- glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
+ RSD_CALL_GL(glGetShaderiv, mShaderID, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLen = 0;
- glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+ RSD_CALL_GL(glGetShaderiv, mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen) {
char* buf = (char*) malloc(infoLen);
if (buf) {
- glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
+ RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
LOGE("Could not compile shader \n%s\n", buf);
free(buf);
}
- glDeleteShader(mShaderID);
+ RSD_CALL_GL(glDeleteShader, mShaderID);
mShaderID = 0;
rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
return false;
@@ -297,24 +297,24 @@
int32_t slot, uint32_t arraySize ) {
RsDataType dataType = field->getType();
if (dataType == RS_TYPE_MATRIX_4X4) {
- glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
+ RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd);
} else if (dataType == RS_TYPE_MATRIX_3X3) {
- glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
+ RSD_CALL_GL(glUniformMatrix3fv, slot, arraySize, GL_FALSE, fd);
} else if (dataType == RS_TYPE_MATRIX_2X2) {
- glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
+ RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd);
} else {
switch (field->getComponent().getVectorSize()) {
case 1:
- glUniform1fv(slot, arraySize, fd);
+ RSD_CALL_GL(glUniform1fv, slot, arraySize, fd);
break;
case 2:
- glUniform2fv(slot, arraySize, fd);
+ RSD_CALL_GL(glUniform2fv, slot, arraySize, fd);
break;
case 3:
- glUniform3fv(slot, arraySize, fd);
+ RSD_CALL_GL(glUniform3fv, slot, arraySize, fd);
break;
case 4:
- glUniform4fv(slot, arraySize, fd);
+ RSD_CALL_GL(glUniform4fv, slot, arraySize, fd);
break;
default:
rsAssert(0);
@@ -351,37 +351,44 @@
if (tex->getHasGraphicsMipmaps() &&
(dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) {
if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+ trans[s->mHal.state.minFilter]);
} else {
switch (trans[s->mHal.state.minFilter]) {
case GL_LINEAR_MIPMAP_LINEAR:
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_NEAREST);
break;
default:
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+ trans[s->mHal.state.minFilter]);
break;
}
}
} else {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+ transNP[s->mHal.state.minFilter]);
}
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[s->mHal.state.magFilter]);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MAG_FILTER,
+ transNP[s->mHal.state.magFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]);
} else {
if (tex->getHasGraphicsMipmaps()) {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+ trans[s->mHal.state.minFilter]);
} else {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+ transNP[s->mHal.state.minFilter]);
}
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]);
+ RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]);
}
float anisoValue = rsMin(dc->gl.gl.EXT_texture_max_aniso, s->mHal.state.aniso);
if (dc->gl.gl.EXT_texture_max_aniso > 1.0f) {
- glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
+ RSD_CALL_GL(glTexParameterf, target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
}
rsdGLCheckError(rsc, "Sampler::setup tex env");
@@ -404,12 +411,12 @@
}
for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
- glActiveTexture(GL_TEXTURE0 + ct);
- glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
+ RSD_CALL_GL(glActiveTexture, GL_TEXTURE0 + ct);
+ RSD_CALL_GL(glUniform1i, sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
if (!mRSProgram->mHal.state.textures[ct].get()) {
// if nothing is bound, reset to default GL texture
- glBindTexture(mTextureTargets[ct], 0);
+ RSD_CALL_GL(glBindTexture, mTextureTargets[ct], 0);
continue;
}
@@ -418,21 +425,22 @@
LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
}
- glBindTexture(drvTex->glTarget, drvTex->textureID);
+ RSD_CALL_GL(glBindTexture, drvTex->glTarget, drvTex->textureID);
rsdGLCheckError(rsc, "ProgramFragment::setup tex bind");
if (mRSProgram->mHal.state.samplers[ct].get()) {
- setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(), mRSProgram->mHal.state.textures[ct].get());
+ setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(),
+ mRSProgram->mHal.state.textures[ct].get());
} else {
- glTexParameteri(drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
rsdGLCheckError(rsc, "ProgramFragment::setup tex env");
}
rsdGLCheckError(rsc, "ProgramFragment::setup uniforms");
}
- glActiveTexture(GL_TEXTURE0);
+ RSD_CALL_GL(glActiveTexture, GL_TEXTURE0);
mDirty = false;
rsdGLCheckError(rsc, "ProgramFragment::setup");
}
@@ -442,7 +450,8 @@
for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
if (!alloc) {
- LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
+ LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set",
+ (uint32_t)this, ct);
rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
continue;
}
@@ -470,7 +479,8 @@
arraySize = sc->fragUniformSize(uidx);
}
if (rsc->props.mLogShadersUniforms) {
- LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
+ LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s",
+ slot, offset, ct, field, uidx, fieldName);
}
uidx ++;
if (slot < 0) {
@@ -528,7 +538,8 @@
}
}
-void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
+void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
+ uint32_t *count, const char *prefix) {
rsAssert(e->getFieldCount());
for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
const Element *ce = e->getField(ct);
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index e3a9cf8..948d51c 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -86,7 +86,9 @@
uint32_t Context::runRootScript() {
timerSet(RS_TIMER_SCRIPT);
mStateFragmentStore.mLast.clear();
+ watchdog.inRoot = true;
uint32_t ret = runScript(mRootScript.get());
+ watchdog.inRoot = false;
return ret;
}
@@ -317,6 +319,13 @@
mExit = true;
}
+void Context::printWatchdogInfo(void *ctx) {
+ Context *rsc = (Context *)ctx;
+ LOGE("RS watchdog timeout: %i %s line %i %s", rsc->watchdog.inRoot,
+ rsc->watchdog.command, rsc->watchdog.line, rsc->watchdog.file);
+}
+
+
void Context::setPriority(int32_t p) {
// Note: If we put this in the proper "background" policy
// the wallpapers can become completly unresponsive at times.
@@ -368,6 +377,7 @@
pthread_mutex_lock(&gInitMutex);
mIO.init();
+ mIO.setTimoutCallback(printWatchdogInfo, this, 2e9);
dev->addContext(this);
mDev = dev;
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 3c7a3d2..199cc5a 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -191,6 +191,19 @@
bool mLogVisual;
} props;
+ mutable struct {
+ bool inRoot;
+ const char *command;
+ const char *file;
+ uint32_t line;
+ } watchdog;
+ static void printWatchdogInfo(void *ctx);
+ void setWatchdogGL(const char *cmd, uint32_t line, const char *file) const {
+ watchdog.command = cmd;
+ watchdog.file = file;
+ watchdog.line = line;
+ }
+
void dumpDebug() const;
void setError(RsError e, const char *msg = NULL) const;
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 4d02269..8879805 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -22,6 +22,9 @@
using namespace android::renderscript;
LocklessCommandFifo::LocklessCommandFifo() : mBuffer(0), mInitialized(false) {
+ mTimeoutCallback = NULL;
+ mTimeoutCallbackData = NULL;
+ mTimeoutWait = 0;
}
LocklessCommandFifo::~LocklessCommandFifo() {
@@ -125,11 +128,21 @@
void LocklessCommandFifo::flush() {
//dumpState("flush 1");
while (mPut != mGet) {
- mSignalToControl.wait();
+ while (!mSignalToControl.wait(mTimeoutWait)) {
+ if (mTimeoutCallback) {
+ mTimeoutCallback(mTimeoutCallbackData);
+ }
+ }
}
//dumpState("flush 2");
}
+void LocklessCommandFifo::setTimoutCallback(void (*cbk)(void *), void *data, uint64_t timeout) {
+ mTimeoutCallback = cbk;
+ mTimeoutCallbackData = data;
+ mTimeoutWait = timeout;
+}
+
bool LocklessCommandFifo::wait(uint64_t timeout) {
while (isEmpty() && !mInShutdown) {
mSignalToControl.set();
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index fa53d40..dafc512 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -34,6 +34,7 @@
public:
bool init(uint32_t size);
void shutdown();
+ void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
void printDebugData() const;
@@ -71,6 +72,10 @@
private:
void dumpState(const char *) const;
+
+ void (*mTimeoutCallback)(void *);
+ void * mTimeoutCallbackData;
+ uint64_t mTimeoutWait;
};
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 3259cb4..7862f3c 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -158,7 +158,7 @@
RsdVertexArray va(attribs, 2);
va.setup(rsc);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4);
}
void rsrDrawQuad(Context *rsc, Script *sc,
@@ -245,7 +245,7 @@
}
void rsrFinish(Context *rsc, Script *sc) {
- glFinish();
+ RSD_CALL_GL(glFinish);
}
@@ -253,16 +253,16 @@
rsc->mFBOCache.setup(rsc);
rsc->setupProgramStore();
- glClearColor(r, g, b, a);
- glClear(GL_COLOR_BUFFER_BIT);
+ RSD_CALL_GL(glClearColor, r, g, b, a);
+ RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT);
}
void rsrClearDepth(Context *rsc, Script *sc, float v) {
rsc->mFBOCache.setup(rsc);
rsc->setupProgramStore();
- glClearDepthf(v);
- glClear(GL_DEPTH_BUFFER_BIT);
+ RSD_CALL_GL(glClearDepthf, v);
+ RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT);
}
uint32_t rsrGetWidth(Context *rsc, Script *sc) {
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index fe2c52e..b1a579a 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -112,6 +112,10 @@
memcpy(data, &mToCoreRet, dataLen);
}
+void ThreadIO::setTimoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
+ mToCore.setTimoutCallback(cb, dat, timeout);
+}
+
bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait) {
bool ret = false;
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index 9036118..ebce0ab 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -39,6 +39,7 @@
// Returns true if any commands were processed.
bool playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait);
+ void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
//LocklessCommandFifo mToCore;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index f5e1416..db27cfd 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -773,20 +773,20 @@
}
public void binderDied() {
- IBinder newModeOwner = null;
+ int newModeOwnerPid = 0;
synchronized(mSetModeDeathHandlers) {
Log.w(TAG, "setMode() client died");
int index = mSetModeDeathHandlers.indexOf(this);
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
} else {
- newModeOwner = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
+ newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
}
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode
- if (newModeOwner != null) {
- disconnectBluetoothSco(newModeOwner);
+ if (newModeOwnerPid != 0) {
+ disconnectBluetoothSco(newModeOwnerPid);
}
}
@@ -817,28 +817,28 @@
return;
}
- IBinder newModeOwner = null;
+ int newModeOwnerPid = 0;
synchronized(mSetModeDeathHandlers) {
if (mode == AudioSystem.MODE_CURRENT) {
mode = mMode;
}
- newModeOwner = setModeInt(mode, cb, Binder.getCallingPid());
+ newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode
- if (newModeOwner != null) {
- disconnectBluetoothSco(newModeOwner);
+ if (newModeOwnerPid != 0) {
+ disconnectBluetoothSco(newModeOwnerPid);
}
}
// must be called synchronized on mSetModeDeathHandlers
- // setModeInt() returns a non null IBInder if the audio mode was successfully set to
+ // setModeInt() returns a valid PID if the audio mode was successfully set to
// any mode other than NORMAL.
- IBinder setModeInt(int mode, IBinder cb, int pid) {
- IBinder newModeOwner = null;
+ int setModeInt(int mode, IBinder cb, int pid) {
+ int newModeOwnerPid = 0;
if (cb == null) {
Log.e(TAG, "setModeInt() called with null binder");
- return newModeOwner;
+ return newModeOwnerPid;
}
SetModeDeathHandler hdlr = null;
@@ -901,13 +901,17 @@
if (status == AudioSystem.AUDIO_STATUS_OK) {
if (mode != AudioSystem.MODE_NORMAL) {
- newModeOwner = cb;
+ if (mSetModeDeathHandlers.isEmpty()) {
+ Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
+ } else {
+ newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
+ }
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false);
}
- return newModeOwner;
+ return newModeOwnerPid;
}
/** pre-condition: oldMode != newMode */
@@ -1351,6 +1355,10 @@
return mCb;
}
+ public int getPid() {
+ return mCreatorPid;
+ }
+
public int totalCount() {
synchronized(mScoClients) {
int count = 0;
@@ -1445,13 +1453,13 @@
}
}
- public void clearAllScoClients(IBinder exceptBinder, boolean stopSco) {
+ public void clearAllScoClients(int exceptPid, boolean stopSco) {
synchronized(mScoClients) {
ScoClient savedClient = null;
int size = mScoClients.size();
for (int i = 0; i < size; i++) {
ScoClient cl = mScoClients.get(i);
- if (cl.getBinder() != exceptBinder) {
+ if (cl.getPid() != exceptPid) {
cl.clearCount(stopSco);
} else {
savedClient = cl;
@@ -1480,7 +1488,7 @@
return result;
}
- private void disconnectBluetoothSco(IBinder exceptBinder) {
+ private void disconnectBluetoothSco(int exceptPid) {
synchronized(mScoClients) {
checkScoAudioState();
if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
@@ -1498,14 +1506,14 @@
}
}
} else {
- clearAllScoClients(exceptBinder, true);
+ clearAllScoClients(exceptPid, true);
}
}
}
private void resetBluetoothSco() {
synchronized(mScoClients) {
- clearAllScoClients(null, false);
+ clearAllScoClients(0, false);
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
@@ -2509,7 +2517,7 @@
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
mScoAudioState = SCO_STATE_INACTIVE;
- clearAllScoClients(null, false);
+ clearAllScoClients(0, false);
break;
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 591a8b9..b566653 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -39,6 +39,8 @@
The caller is expected to know the type of the metadata and call
the right get* method to fetch its value.
+
+ @hide
*/
public class Metadata
{
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index daa25e0..f66f1b0 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -16,7 +16,9 @@
package android.media;
+import android.app.PendingIntent;
import android.content.ComponentName;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -203,6 +205,8 @@
public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
/**
+ * @hide
+ * TODO remove after modifying known (internal) media apps using this API
* Class constructor.
* @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
* been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
@@ -226,6 +230,8 @@
}
/**
+ * @hide
+ * TODO remove after modifying known (internal) media apps using this API
* Class constructor for a remote control client whose internal event handling
* happens on a user-provided Looper.
* @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
@@ -242,6 +248,56 @@
mEventHandler = new EventHandler(this, looper);
}
+ /**
+ * Class constructor.
+ * @param mediaButtonIntent The intent that will be sent for the media button events sent
+ * by remote controls.
+ * This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
+ * action, and have a component that will handle the intent (set with
+ * {@link Intent#setComponent(ComponentName)}) registered with
+ * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
+ * before this new RemoteControlClient can itself be registered with
+ * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
+ * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
+ * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
+ */
+ public RemoteControlClient(PendingIntent mediaButtonIntent) {
+ // TODO implement using PendingIntent instead of ComponentName
+ mRcEventReceiver = null;
+
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else {
+ mEventHandler = null;
+ Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
+ }
+ }
+
+ /**
+ * Class constructor for a remote control client whose internal event handling
+ * happens on a user-provided Looper.
+ * @param mediaButtonIntent The intent that will be sent for the media button events sent
+ * by remote controls.
+ * This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
+ * action, and have a component that will handle the intent (set with
+ * {@link Intent#setComponent(ComponentName)}) registered with
+ * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
+ * before this new RemoteControlClient can itself be registered with
+ * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
+ * @param looper The Looper running the event loop.
+ * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
+ * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
+ */
+ public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
+ // TODO implement using PendingIntent instead of ComponentName
+ mRcEventReceiver = null;
+
+ mEventHandler = new EventHandler(this, looper);
+ }
+
private static final int[] METADATA_KEYS_TYPE_STRING = {
MediaMetadataRetriever.METADATA_KEY_ALBUM,
MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c2c6715..8ebb652 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -262,7 +262,7 @@
mFlushed = false;
mFlags = flags;
AudioSystem::acquireAudioSessionId(mSessionId);
-
+ mRestoreStatus = NO_ERROR;
return NO_ERROR;
}
@@ -1161,8 +1161,8 @@
status_t result;
if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
- LOGW("dead IAudioTrack, creating a new one from %s",
- fromStart ? "start()" : "obtainBuffer()");
+ LOGW("dead IAudioTrack, creating a new one from %s TID %d",
+ fromStart ? "start()" : "obtainBuffer()", gettid());
// signal old cblk condition so that other threads waiting for available buffers stop
// waiting now
@@ -1217,33 +1217,35 @@
}
if (mActive) {
result = mAudioTrack->start();
+ LOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
}
if (fromStart && result == NO_ERROR) {
mNewPosition = mCblk->server + mUpdatePeriod;
}
}
if (result != NO_ERROR) {
- mActive = false;
+ android_atomic_and(~CBLK_RESTORING_ON, &cblk->flags);
+ LOGW_IF(result != NO_ERROR, "restoreTrack_l() failed status %d", result);
}
-
+ mRestoreStatus = result;
// signal old cblk condition for other threads waiting for restore completion
android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
cblk->cv.broadcast();
} else {
if (!(cblk->flags & CBLK_RESTORED_MSK)) {
- LOGW("dead IAudioTrack, waiting for a new one");
+ LOGW("dead IAudioTrack, waiting for a new one TID %d", gettid());
mLock.unlock();
result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+ if (result == NO_ERROR) {
+ result = mRestoreStatus;
+ }
cblk->lock.unlock();
mLock.lock();
} else {
- LOGW("dead IAudioTrack, already restored");
- result = NO_ERROR;
+ LOGW("dead IAudioTrack, already restored TID %d", gettid());
+ result = mRestoreStatus;
cblk->lock.unlock();
}
- if (result != NO_ERROR || mActive == 0) {
- result = status_t(STOPPED);
- }
}
LOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
@@ -1254,7 +1256,7 @@
}
cblk->lock.lock();
- LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result);
+ LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d TID %d", result, gettid());
return result;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8f213da..bf83849 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,6 +26,9 @@
namespace android {
+// static
+const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+
NuPlayer::Renderer::Renderer(
const sp<MediaPlayerBase::AudioSink> &sink,
const sp<AMessage> ¬ify)
@@ -43,7 +46,8 @@
mHasAudio(false),
mHasVideo(false),
mSyncQueues(false),
- mPaused(false) {
+ mPaused(false),
+ mLastPositionUpdateUs(-1ll) {
}
NuPlayer::Renderer::~Renderer() {
@@ -190,7 +194,7 @@
mDrainAudioQueuePending = true;
sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
msg->setInt32("generation", mAudioQueueGeneration);
- msg->post(10000);
+ msg->post();
}
void NuPlayer::Renderer::signalAudioSinkChanged() {
@@ -198,7 +202,6 @@
}
void NuPlayer::Renderer::onDrainAudioQueue() {
-
for (;;) {
if (mAudioQueue.empty()) {
break;
@@ -562,6 +565,13 @@
}
int64_t nowUs = ALooper::GetNowUs();
+
+ if (mLastPositionUpdateUs >= 0
+ && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
+ return;
+ }
+ mLastPositionUpdateUs = nowUs;
+
int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
sp<AMessage> notify = mNotify->dup();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 2713031..3a641a2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -74,6 +74,8 @@
status_t mFinalResult;
};
+ static const int64_t kMinPositionUpdateDelayUs;
+
sp<MediaPlayerBase::AudioSink> mAudioSink;
sp<AMessage> mNotify;
List<QueueEntry> mAudioQueue;
@@ -98,6 +100,8 @@
bool mPaused;
+ int64_t mLastPositionUpdateUs;
+
void onDrainAudioQueue();
void postDrainAudioQueue();
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e9dc61c..2ba2273 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1131,6 +1131,13 @@
mSentFormat = true;
}
+void ACodec::signalError(OMX_ERRORTYPE error) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", ACodec::kWhatError);
+ notify->setInt32("omx-error", error);
+ notify->post();
+}
+
////////////////////////////////////////////////////////////////////////////////
ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -1252,10 +1259,7 @@
LOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1);
- sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", ACodec::kWhatError);
- notify->setInt32("omx-error", data1);
- notify->post();
+ mCodec->signalError((OMX_ERRORTYPE)data1);
return true;
}
@@ -1548,12 +1552,14 @@
&& msg->findInt32("render", &render) && render != 0) {
// The client wants this buffer to be rendered.
- CHECK_EQ(mCodec->mNativeWindow->queueBuffer(
+ if (mCodec->mNativeWindow->queueBuffer(
mCodec->mNativeWindow.get(),
- info->mGraphicBuffer.get()),
- 0);
-
- info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
+ info->mGraphicBuffer.get()) == OK) {
+ info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
+ } else {
+ mCodec->signalError();
+ info->mStatus = BufferInfo::OWNED_BY_US;
+ }
} else {
info->mStatus = BufferInfo::OWNED_BY_US;
}
@@ -1692,11 +1698,7 @@
if (node == NULL) {
LOGE("Unable to instantiate a decoder for type '%s'.", mime.c_str());
- sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", ACodec::kWhatError);
- notify->setInt32("omx-error", OMX_ErrorComponentNotFound);
- notify->post();
-
+ mCodec->signalError(OMX_ErrorComponentNotFound);
return;
}
@@ -1744,10 +1746,7 @@
"(error 0x%08x)",
err);
- sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", ACodec::kWhatError);
- notify->setInt32("omx-error", OMX_ErrorUndefined);
- notify->post();
+ mCodec->signalError();
}
}
@@ -2063,10 +2062,7 @@
"port reconfiguration (error 0x%08x)",
err);
- sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", ACodec::kWhatError);
- notify->setInt32("omx-error", OMX_ErrorUndefined);
- notify->post();
+ mCodec->signalError();
}
return true;
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 6313ca3..4e46414 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -117,14 +117,12 @@
}
}
- int64_t timeUs =
- (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
-
off64_t offset;
size_t size;
bool isKey;
+ int64_t timeUs;
status_t err = mExtractor->getSampleInfo(
- mTrackIndex, mSampleIndex, &offset, &size, &isKey);
+ mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
++mSampleIndex;
@@ -396,6 +394,8 @@
uint32_t rate = U32LE_AT(&data[20]);
uint32_t scale = U32LE_AT(&data[24]);
+ uint32_t sampleSize = U32LE_AT(&data[44]);
+
const char *mime = NULL;
Track::Kind kind = Track::OTHER;
@@ -427,6 +427,7 @@
track->mMeta = meta;
track->mRate = rate;
track->mScale = scale;
+ track->mBytesPerSample = sampleSize;
track->mKind = kind;
track->mNumSyncSamples = 0;
track->mThumbnailSampleSize = 0;
@@ -612,11 +613,12 @@
off64_t offset;
size_t size;
bool isKey;
- status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
+ int64_t timeUs;
+ status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
if (err != OK) {
mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
- err = getSampleInfo(0, 0, &offset, &size, &isKey);
+ err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
if (err != OK) {
return err;
@@ -630,8 +632,9 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
Track *track = &mTracks.editItemAt(i);
- int64_t durationUs =
- (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
+ int64_t durationUs;
+ CHECK_EQ((status_t)OK,
+ getSampleTime(i, track->mSamples.size() - 1, &durationUs));
LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
@@ -645,9 +648,10 @@
if (!strncasecmp("video/", mime.c_str(), 6)
&& track->mThumbnailSampleIndex >= 0) {
- int64_t thumbnailTimeUs =
- (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
- / track->mScale;
+ int64_t thumbnailTimeUs;
+ CHECK_EQ((status_t)OK,
+ getSampleTime(i, track->mThumbnailSampleIndex,
+ &thumbnailTimeUs));
track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
@@ -659,6 +663,21 @@
}
}
}
+
+ if (track->mBytesPerSample != 0) {
+ // Assume all chunks are the same size for now.
+
+ off64_t offset;
+ size_t size;
+ bool isKey;
+ int64_t sampleTimeUs;
+ CHECK_EQ((status_t)OK,
+ getSampleInfo(
+ i, 0,
+ &offset, &size, &isKey, &sampleTimeUs));
+
+ track->mRate *= size / track->mBytesPerSample;
+ }
}
mFoundIndex = true;
@@ -720,7 +739,9 @@
off64_t offset;
size_t size;
bool isKey;
- status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
+ int64_t timeUs;
+ status_t err =
+ getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
if (err != OK) {
return err;
@@ -762,7 +783,8 @@
status_t AVIExtractor::getSampleInfo(
size_t trackIndex, size_t sampleIndex,
- off64_t *offset, size_t *size, bool *isKey) {
+ off64_t *offset, size_t *size, bool *isKey,
+ int64_t *sampleTimeUs) {
if (trackIndex >= mTracks.size()) {
return -ERANGE;
}
@@ -801,9 +823,20 @@
*isKey = info.mIsKey;
+ *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
+
return OK;
}
+status_t AVIExtractor::getSampleTime(
+ size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
+ off64_t offset;
+ size_t size;
+ bool isKey;
+ return getSampleInfo(
+ trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
+}
+
status_t AVIExtractor::getSampleIndexAtTime(
size_t trackIndex,
int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
@@ -911,7 +944,11 @@
if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
- *confidence = 0.2;
+
+ // Just a tad over the mp3 extractor's confidence, since
+ // these .avi files may contain .mp3 content that otherwise would
+ // mistakenly lead to us identifying the entire file as a .mp3 file.
+ *confidence = 0.21;
return true;
}
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 375a94d..b575347 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -54,6 +54,11 @@
uint32_t mRate;
uint32_t mScale;
+ // If bytes per sample == 0, each chunk represents a single sample,
+ // otherwise each chunk should me a multiple of bytes-per-sample in
+ // size.
+ uint32_t mBytesPerSample;
+
enum Kind {
AUDIO,
VIDEO,
@@ -84,7 +89,11 @@
status_t getSampleInfo(
size_t trackIndex, size_t sampleIndex,
- off64_t *offset, size_t *size, bool *isKey);
+ off64_t *offset, size_t *size, bool *isKey,
+ int64_t *sampleTimeUs);
+
+ status_t getSampleTime(
+ size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
status_t getSampleIndexAtTime(
size_t trackIndex,
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java
index afe2001..2a02b58 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorAPITest.java
@@ -2590,12 +2590,15 @@
+ "H264_BP_1920x1080_30fps_1200Kbps_1_10.mp4";
final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
final MediaVideoItem mediaVideoItem1;
- boolean flagForException = false;
+ // 1080p resolution is supported on some devices
+ // but not on other devices.
+ // So this test case is not generic and
+ // hence we always assert true
+ boolean flagForException = true;
try {
mediaVideoItem1 = mVideoEditorHelper.createMediaItem(mVideoEditor,
"m1", videoItemFileName1, renderingMode);
} catch (IllegalArgumentException e) {
- flagForException = true;
}
assertTrue("VideoContent 1920x1080", flagForException);
}
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml
index 19848f6..f3feee8 100644
--- a/packages/BackupRestoreConfirmation/AndroidManifest.xml
+++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml
@@ -25,6 +25,7 @@
android:permission="android.permission.CONFIRM_FULL_BACKUP" >
<activity android:name=".BackupRestoreConfirmation"
+ android:title=""
android:windowSoftInputMode="stateAlwaysHidden"
android:excludeFromRecents="true"
android:exported="true" >
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
index 3522e7c..2ee74fe 100644
--- a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
@@ -21,10 +21,10 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="16dp" >
+ android:orientation="vertical">
<ScrollView
+ android:padding="16dp"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent">
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
index f022e57..e207a98 100644
--- a/packages/BackupRestoreConfirmation/res/values/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -14,6 +14,10 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title of the activity when a full backup has been requested and must be confirmed -->
+ <string name="backup_confirm_title">Full backup</string>
+ <!-- Title of the activity when a full restore has been requested and must be confirmed -->
+ <string name="restore_confirm_title">Full restore</string>
<!-- Text for message to user that a full backup has been requested, and must be confirmed. -->
<string name="backup_confirm_text">A full backup of all data to a connected desktop computer has been requested. Do you want to allow this to happen\?\n\nIf you did not request the backup yourself, do not allow the operation to proceed.</string>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index 5448e0b..d053f29 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -131,10 +131,13 @@
final String action = intent.getAction();
final int layoutId;
+ final int titleId;
if (action.equals(FullBackup.FULL_BACKUP_INTENT_ACTION)) {
layoutId = R.layout.confirm_backup;
+ titleId = R.string.backup_confirm_title;
} else if (action.equals(FullBackup.FULL_RESTORE_INTENT_ACTION)) {
layoutId = R.layout.confirm_restore;
+ titleId = R.string.restore_confirm_title;
} else {
Slog.w(TAG, "Backup/restore confirmation activity launched with invalid action!");
finish();
@@ -159,6 +162,7 @@
mObserver.setHandler(mHandler);
}
+ setTitle(titleId);
setContentView(layoutId);
// Same resource IDs for each layout variant (backup / restore)
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 0f47482..319eb8d 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.defcontainer">
+ package="com.android.defcontainer" coreApp="true">
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
<uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>
<uses-permission android:name="android.permission.ASEC_ACCESS"/>
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index dd0d064..0719426 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.providers.settings"
+ coreApp="true"
android:sharedUserId="android.uid.system">
<application android:allowClearUserData="false"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d10911f..a2452c4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.systemui"
+ coreApp="true"
android:sharedUserId="android.uid.system"
android:process="system"
>
diff --git a/packages/SystemUI/res/drawable/notification_list_shadow.xml b/packages/SystemUI/res/drawable/notification_list_shadow.xml
new file mode 100644
index 0000000..7f33153
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_list_shadow.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <gradient
+ android:angle="90"
+ android:endColor="@color/notification_list_shadow_top"
+ android:startColor="#00000000"
+ android:type="linear"
+ />
+</shape>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index eae3e52..167d362 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -42,6 +42,7 @@
<ImageView android:id="@+id/app_thumbnail_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:visibility="invisible"
/>
</FrameLayout>
@@ -71,6 +72,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:visibility="invisible"
+ android:textColor="@color/status_bar_recents_app_label_color"
/>
<TextView android:id="@+id/app_description"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index b14ef595..de80a51 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -40,6 +40,7 @@
<ImageView android:id="@+id/app_thumbnail_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:visibility="invisible"
/>
</FrameLayout>
@@ -67,6 +68,7 @@
android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
android:singleLine="true"
android:ellipsize="marquee"
+ android:textColor="@color/status_bar_recents_app_label_color"
/>
<View android:id="@+id/recents_callout_line"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index f4be651..07088d5 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -35,6 +35,7 @@
<ImageView android:id="@+id/app_thumbnail_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:visibility="invisible"
/>
</FrameLayout>
@@ -63,6 +64,7 @@
android:layout_marginTop="32dip"
android:singleLine="true"
android:ellipsize="marquee"
+ android:textColor="@color/status_bar_recents_app_label_color"
/>
<View android:id="@+id/recents_callout_line"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0b3fb98..f9f31ca 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -32,6 +32,7 @@
android:paddingTop="3dp"
android:paddingBottom="5dp"
android:paddingRight="3dp"
+ android:background="@drawable/notification_header_bg"
>
<com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
@@ -104,12 +105,25 @@
android:fadingEdge="none"
android:overScrollMode="ifContentScrolls"
>
- <com.android.systemui.statusbar.policy.NotificationRowLayout
- android:id="@+id/latestItems"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- systemui:rowHeight="@dimen/notification_height"
+ android:orientation="vertical"
+ >
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
+ android:id="@+id/latestItems"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ systemui:rowHeight="@dimen/notification_height"
+ android:background="@color/notification_list_shadow_top"
+ />
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="16dp"
+ android:src="@drawable/notification_list_shadow"
+ android:scaleType="fitXY"
/>
+ </LinearLayout>
</ScrollView>
<ImageView
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index 894248e..25c0237 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -30,7 +30,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:background="@drawable/status_bar_bg"
+ android:background="@drawable/notification_tracking_bg"
/>
<com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4c222f9..298536b4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -23,5 +23,9 @@
<drawable name="status_bar_background">#ff000000</drawable>
<drawable name="status_bar_recents_background">#b3000000</drawable>
<drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
+ <color name="status_bar_recents_app_label_color">#ffffffff</color>
<drawable name="status_bar_notification_row_background_color">#ff000000</drawable>
+ <drawable name="notification_header_bg">#FF000000</drawable>
+ <drawable name="notification_tracking_bg">#cc111315</drawable>
+ <color name="notification_list_shadow_top">#80000000</color>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 0354fd7..07281d4 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -41,9 +41,10 @@
public static final int Y = 1;
private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
- private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms
- private int MAX_DISMISS_VELOCITY = 1000; // dp/sec
- private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
+ private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
+ private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
+ private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
+ private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
// where fade starts
@@ -126,7 +127,10 @@
} else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
}
- return result;
+ // Make .03 alpha the minimum so you always see the item a bit-- slightly below
+ // .03, the item disappears entirely (as if alpha = 0) and that discontinuity looks
+ // a bit jarring
+ return Math.max(0.03f, result);
}
// invalidate the view's own bounds all the way up the view hierarchy
@@ -186,6 +190,7 @@
}
break;
case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
mDragging = false;
mCurrView = null;
mCurrAnimView = null;
@@ -212,7 +217,10 @@
duration = Math.min(duration,
(int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
.abs(velocity)));
+ } else {
+ duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
}
+
ObjectAnimator anim = createTranslationAnimation(animView, newPos);
anim.setInterpolator(new LinearInterpolator());
anim.setDuration(duration);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index fc03a27..1c9d80d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -44,15 +44,6 @@
private SwipeHelper mSwipeHelper;
private RecentsScrollViewPerformanceHelper mPerformanceHelper;
- private OnLongClickListener mOnLongClick = new OnLongClickListener() {
- public boolean onLongClick(View v) {
- final View anchorView = v.findViewById(R.id.app_description);
- final View thumbnailView = v.findViewById(R.id.app_thumbnail);
- mCallback.handleLongPress(v, anchorView, thumbnailView);
- return true;
- }
- };
-
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
float densityScale = getResources().getDisplayMetrics().density;
@@ -69,8 +60,6 @@
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
final View view = mAdapter.getView(i, null, mLinearLayout);
- view.setLongClickable(true);
- view.setOnLongClickListener(mOnLongClick);
if (mPerformanceHelper != null) {
mPerformanceHelper.addViewCallback(view);
@@ -81,18 +70,30 @@
mCallback.dismiss();
}
});
+ // We don't want a click sound when we dimiss recents
+ view.setSoundEffectsEnabled(false);
OnClickListener launchAppListener = new OnClickListener() {
public void onClick(View v) {
mCallback.handleOnClick(view);
}
};
+ OnLongClickListener longClickListener = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = view.findViewById(R.id.app_description);
+ final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+ mCallback.handleLongPress(view, anchorView, thumbnailView);
+ return true;
+ }
+ };
final View thumbnail = view.findViewById(R.id.app_thumbnail);
thumbnail.setClickable(true);
thumbnail.setOnClickListener(launchAppListener);
+ thumbnail.setOnLongClickListener(longClickListener);
final View appTitle = view.findViewById(R.id.app_label);
appTitle.setClickable(true);
appTitle.setOnClickListener(launchAppListener);
+ appTitle.setOnLongClickListener(longClickListener);
mLinearLayout.addView(view);
}
// Scroll to end after layout.
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index f7afe3a..0621b22 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -186,12 +186,6 @@
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
- /* StateListDrawable thumbnailForegroundDrawable = new StateListDrawable();
- thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_pressed },
- mPressedDrawable);
- thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_selected },
- mPressedDrawable);
- ((FrameLayout)holder.thumbnailView).setForeground(thumbnailForegroundDrawable);*/
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b12387a..213803c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -43,15 +43,6 @@
private SwipeHelper mSwipeHelper;
private RecentsScrollViewPerformanceHelper mPerformanceHelper;
- private OnLongClickListener mOnLongClick = new OnLongClickListener() {
- public boolean onLongClick(View v) {
- final View anchorView = v.findViewById(R.id.app_description);
- final View thumbnailView = v.findViewById(R.id.app_thumbnail);
- mCallback.handleLongPress(v, anchorView, thumbnailView);
- return true;
- }
- };
-
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
float densityScale = getResources().getDisplayMetrics().density;
@@ -83,28 +74,39 @@
}
if (old == null) {
- view.setClickable(true);
- view.setOnLongClickListener(mOnLongClick);
view.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mCallback.dismiss();
}
});
+ // We don't want a click sound when we dimiss recents
+ view.setSoundEffectsEnabled(false);
OnClickListener launchAppListener = new OnClickListener() {
public void onClick(View v) {
mCallback.handleOnClick(view);
}
};
+ OnLongClickListener longClickListener = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = view.findViewById(R.id.app_description);
+ final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+ mCallback.handleLongPress(view, anchorView, thumbnailView);
+ return true;
+ }
+ };
final View thumbnail = view.findViewById(R.id.app_thumbnail);
thumbnail.setClickable(true);
thumbnail.setOnClickListener(launchAppListener);
+ thumbnail.setOnLongClickListener(longClickListener);
final View appTitle = view.findViewById(R.id.app_label);
appTitle.setClickable(true);
appTitle.setOnClickListener(launchAppListener);
+ appTitle.setOnLongClickListener(longClickListener);
final View calloutLine = view.findViewById(R.id.recents_callout_line);
calloutLine.setClickable(true);
calloutLine.setOnClickListener(launchAppListener);
+ calloutLine.setOnLongClickListener(longClickListener);
mLinearLayout.addView(view);
}
}
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 69e0752..0b65d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1458,9 +1458,10 @@
Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+ mDisabled);
} else if (CHATTY) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (event.getAction() != MotionEvent.ACTION_MOVE) {
Slog.d(TAG, String.format(
- "panel: ACTION_DOWN at (%f, %f) mDisabled=0x%08x",
+ "panel: %s at (%f, %f) mDisabled=0x%08x",
+ MotionEvent.actionToString(event.getAction()),
event.getRawX(), event.getRawY(), mDisabled));
}
}
@@ -1469,11 +1470,11 @@
return false;
}
+ final int action = event.getAction();
final int statusBarSize = mStatusBarView.getHeight();
final int hitSize = statusBarSize*2;
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- final int y = (int)event.getRawY();
-
+ final int y = (int)event.getRawY();
+ if (action == MotionEvent.ACTION_DOWN) {
if (!mExpanded) {
mViewDelta = statusBarSize - y;
} else {
@@ -1490,21 +1491,21 @@
final int edgeBorder = mEdgeBorder;
if (x >= edgeBorder && x < mDisplayMetrics.widthPixels - edgeBorder) {
prepareTracking(y, !mExpanded);// opening if we're not already fully visible
- mVelocityTracker.addMovement(event);
+ trackMovement(event);
}
}
} else if (mTracking) {
- mVelocityTracker.addMovement(event);
+ trackMovement(event);
final int minY = statusBarSize + mCloseView.getHeight();
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- int y = (int)event.getRawY();
+ if (action == MotionEvent.ACTION_MOVE) {
if (mAnimatingReveal && y < minY) {
// nothing
} else {
mAnimatingReveal = false;
updateExpandedViewPos(y + mViewDelta);
}
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ } else if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_CANCEL) {
mVelocityTracker.computeCurrentVelocity(1000);
float yVel = mVelocityTracker.getYVelocity();
@@ -1531,13 +1532,23 @@
vel));
}
- performFling((int)event.getRawY(), vel, false);
+ performFling(y + mViewDelta, vel, false);
}
}
return false;
}
+ private void trackMovement(MotionEvent event) {
+ // Add movement to velocity tracker using raw screen X and Y coordinates instead
+ // of window coordinates because the window frame may be moving at the same time.
+ float deltaX = event.getRawX() - event.getX();
+ float deltaY = event.getRawY() - event.getY();
+ event.offsetLocation(deltaX, deltaY);
+ mVelocityTracker.addMovement(event);
+ event.offsetLocation(-deltaX, -deltaY);
+ }
+
@Override // CommandQueue
public void setSystemUiVisibility(int vis) {
final int old = mSystemUiVisibility;
@@ -1834,7 +1845,7 @@
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- PixelFormat.OPAQUE);
+ PixelFormat.TRANSLUCENT);
if (ActivityManager.isHighEndGfx(mDisplay)) {
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 840087c..3a06068 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -16,12 +16,10 @@
package com.android.systemui.statusbar.policy;
-import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.Canvas;
import android.graphics.RectF;
@@ -29,7 +27,6 @@
import android.os.SystemClock;
import android.os.ServiceManager;
import android.util.AttributeSet;
-import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
@@ -40,9 +37,7 @@
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.ViewGroup;
import android.widget.ImageView;
-import android.widget.RemoteViews.RemoteView;
import com.android.systemui.R;
@@ -53,9 +48,7 @@
IWindowManager mWindowManager;
long mDownTime;
- boolean mSending;
int mCode;
- int mRepeat;
int mTouchSlop;
Drawable mGlowBG;
float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
@@ -67,12 +60,7 @@
if (isPressed()) {
// Slog.d("KeyButtonView", "longpressed: " + this);
if (mCode != 0) {
- mRepeat++;
- sendEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.FLAG_FROM_SYSTEM
- | KeyEvent.FLAG_VIRTUAL_HARD_KEY
- | KeyEvent.FLAG_LONG_PRESS);
-
+ sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
} else {
// Just an old-fashioned ImageView
@@ -217,64 +205,54 @@
case MotionEvent.ACTION_DOWN:
//Slog.d("KeyButtonView", "press");
mDownTime = SystemClock.uptimeMillis();
- mRepeat = 0;
- mSending = true;
setPressed(true);
- sendEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime);
+ if (mCode != 0) {
+ sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
+ } else {
+ // Provide the same haptic feedback that the system offers for virtual keys.
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ }
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
- } else {
- mSending = false;
- sendEvent(KeyEvent.ACTION_UP,
- KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime);
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
- playSoundEffect(SoundEffectConstants.CLICK);
}
break;
case MotionEvent.ACTION_MOVE:
- if (mSending) {
- x = (int)ev.getX();
- y = (int)ev.getY();
- setPressed(x >= -mTouchSlop
- && x < getWidth() + mTouchSlop
- && y >= -mTouchSlop
- && y < getHeight() + mTouchSlop);
- }
+ x = (int)ev.getX();
+ y = (int)ev.getY();
+ setPressed(x >= -mTouchSlop
+ && x < getWidth() + mTouchSlop
+ && y >= -mTouchSlop
+ && y < getHeight() + mTouchSlop);
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
- if (mSending) {
- mSending = false;
- sendEvent(KeyEvent.ACTION_UP,
- KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
- | KeyEvent.FLAG_CANCELED);
- if (mSupportsLongpress) {
- removeCallbacks(mCheckLongPress);
- }
+ if (mCode != 0) {
+ sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
+ }
+ if (mSupportsLongpress) {
+ removeCallbacks(mCheckLongPress);
}
break;
case MotionEvent.ACTION_UP:
final boolean doIt = isPressed();
setPressed(false);
- if (mSending) {
- mSending = false;
- final int flags = KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY;
- if (mSupportsLongpress) {
- removeCallbacks(mCheckLongPress);
- }
-
- if (mCode != 0) {
- if (doIt) {
- sendEvent(KeyEvent.ACTION_UP, flags);
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
- playSoundEffect(SoundEffectConstants.CLICK);
- }
+ if (mCode != 0) {
+ if (doIt) {
+ sendEvent(KeyEvent.ACTION_UP, 0);
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ playSoundEffect(SoundEffectConstants.CLICK);
} else {
- // no key code, just a regular ImageView
- if (doIt) performClick();
+ sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
+ } else {
+ // no key code, just a regular ImageView
+ if (doIt) {
+ performClick();
+ }
+ }
+ if (mSupportsLongpress) {
+ removeCallbacks(mCheckLongPress);
}
break;
}
@@ -287,8 +265,11 @@
}
void sendEvent(int action, int flags, long when) {
- final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat,
- 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags, InputDevice.SOURCE_KEYBOARD);
+ final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
+ final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
+ 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+ InputDevice.SOURCE_KEYBOARD);
try {
//Slog.d(TAG, "injecting event " + ev);
mWindowManager.injectInputEventNoWait(ev);
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
index 3dcbb46..ec710ff 100644
--- a/packages/VpnDialogs/res/layout/manage.xml
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -19,7 +19,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3mm"
- android:stretchColumns="0,1">
+ android:stretchColumns="0,1"
+ android:shrinkColumns="1">
<TableRow>
<TextView android:text="@string/session" style="@style/label"/>
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index df6d36b..fcd58fa 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -35,8 +35,8 @@
<string name="session">Session:</string>
<string name="duration">Duration:</string>
- <string name="data_transmitted">Data Transmitted:</string>
- <string name="data_received">Data Received:</string>
+ <string name="data_transmitted">Sent:</string>
+ <string name="data_received">Received:</string>
<string name="blank_value">--</string>
<string name="data_value_format">
diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml
index 6eae218..cf10596 100644
--- a/packages/VpnDialogs/res/values/styles.xml
+++ b/packages/VpnDialogs/res/values/styles.xml
@@ -24,7 +24,7 @@
<style name="label">
<item name="android:gravity">center_vertical|right</item>
- <item name="android:paddingRight">5mm</item>
+ <item name="android:paddingRight">2mm</item>
<item name="android:textSize">16sp</item>
</style>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 86671bd..9b51eb0 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -629,15 +629,6 @@
mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
}
- /**
- * When a home-key longpress expires, close other system windows and launch the recent apps
- */
- Runnable mHomeLongPress = new Runnable() {
- public void run() {
- handleLongPressOnHome();
- }
- };
-
private void handleLongPressOnHome() {
// We can't initialize this in init() since the configuration hasn't been loaded yet.
if (mLongPressOnHomeBehavior < 0) {
@@ -1418,11 +1409,6 @@
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
- // Clear a pending HOME longpress if the user releases Home
- if (!down) {
- mHandler.removeCallbacks(mHomeLongPress);
- }
-
// If we have released the home key, and didn't do anything else
// while it was pressed, then it is time to go home!
if (mHomePressed && !down) {
@@ -1470,12 +1456,15 @@
}
}
}
-
- if (down && repeatCount == 0) {
- if (!keyguardOn) {
- mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+
+ if (down) {
+ if (repeatCount == 0) {
+ mHomePressed = true;
+ } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ if (!keyguardOn) {
+ handleLongPressOnHome();
+ }
}
- mHomePressed = true;
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
@@ -2180,7 +2169,17 @@
if (topIsFullscreen) {
if (mStatusBarCanHide) {
if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
- if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ if (mStatusBar.hideLw(true)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+
+ mHandler.post(new Runnable() { public void run() {
+ if (mStatusBarService != null) {
+ try {
+ mStatusBarService.collapse();
+ } catch (RemoteException ex) {}
+ }
+ }});
+ }
} else if (localLOGV) {
Log.v(TAG, "Preventing status bar from hiding by policy");
}
@@ -2518,7 +2517,8 @@
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
}
- if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+ if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+ && event.getRepeatCount() == 0) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 94efa74..a58f64c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -87,6 +87,8 @@
// RecordThread loop sleep time upon application overrun or audio HAL read error
static const int kRecordThreadSleepUs = 5000;
+static const nsecs_t kSetParametersTimeout = seconds(2);
+
// ----------------------------------------------------------------------------
static bool recordingAllowed() {
@@ -1032,7 +1034,7 @@
mWaitWorkCV.signal();
// wait condition with timeout in case the thread loop has exited
// before the request could be processed
- if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+ if (mParamCond.waitRelative(mLock, kSetParametersTimeout) == NO_ERROR) {
status = mParamStatus;
mWaitWorkCV.signal();
} else {
@@ -2349,7 +2351,9 @@
mParamStatus = status;
mParamCond.signal();
- mWaitWorkCV.wait(mLock);
+ // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+ // already timed out waiting for the status and will never signal the condition.
+ mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
}
return reconfig;
}
@@ -2828,7 +2832,9 @@
mParamStatus = status;
mParamCond.signal();
- mWaitWorkCV.wait(mLock);
+ // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+ // already timed out waiting for the status and will never signal the condition.
+ mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
}
return reconfig;
}
@@ -4669,7 +4675,9 @@
mParamStatus = status;
mParamCond.signal();
- mWaitWorkCV.wait(mLock);
+ // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+ // already timed out waiting for the status and will never signal the condition.
+ mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
}
return reconfig;
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index be2ef82..2938c45 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -497,10 +497,14 @@
case MSG_RUN_FULL_BACKUP:
{
+ // TODO: refactor full backup to be a looper-based state machine
+ // similar to normal backup/restore.
FullBackupParams params = (FullBackupParams)msg.obj;
- (new PerformFullBackupTask(params.fd, params.observer, params.includeApks,
+ PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
+ params.observer, params.includeApks,
params.includeShared, params.curPassword, params.encryptPassword,
- params.allApps, params.packages, params.latch)).run();
+ params.allApps, params.packages, params.latch);
+ (new Thread(task)).start();
break;
}
@@ -519,9 +523,13 @@
case MSG_RUN_FULL_RESTORE:
{
+ // TODO: refactor full restore to be a looper-based state machine
+ // similar to normal backup/restore.
FullRestoreParams params = (FullRestoreParams)msg.obj;
- (new PerformFullRestoreTask(params.fd, params.curPassword, params.encryptPassword,
- params.observer, params.latch)).run();
+ PerformFullRestoreTask task = new PerformFullRestoreTask(params.fd,
+ params.curPassword, params.encryptPassword,
+ params.observer, params.latch);
+ (new Thread(task)).start();
break;
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index bbc26d6..bb21d81 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -235,6 +235,7 @@
private boolean mPreventScreenOn;
private int mScreenBrightnessOverride = -1;
private int mButtonBrightnessOverride = -1;
+ private int mScreenBrightnessDim;
private boolean mUseSoftwareAutoBrightness;
private boolean mAutoBrightessEnabled;
private int[] mAutoBrightnessLevels;
@@ -586,6 +587,9 @@
mUnplugTurnsOnScreen = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
+ mScreenBrightnessDim = resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDim);
+
// read settings for auto-brightness
mUseSoftwareAutoBrightness = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
@@ -1880,7 +1884,7 @@
nominalCurrentValue = preferredBrightness;
break;
case SCREEN_ON_BIT:
- nominalCurrentValue = Power.BRIGHTNESS_DIM;
+ nominalCurrentValue = mScreenBrightnessDim;
break;
case 0:
nominalCurrentValue = Power.BRIGHTNESS_OFF;
@@ -1899,7 +1903,7 @@
// the scale is because the brightness ramp isn't linear and this biases
// it so the later parts take longer.
final float scale = 1.5f;
- float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
+ float ratio = (((float)mScreenBrightnessDim)/preferredBrightness);
if (ratio > 1.0f) ratio = 1.0f;
if ((newState & SCREEN_ON_BIT) == 0) {
if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
@@ -1926,7 +1930,7 @@
// will then count going dim as turning off.
mScreenOffTime = SystemClock.elapsedRealtime();
}
- brightness = Power.BRIGHTNESS_DIM;
+ brightness = mScreenBrightnessDim;
}
}
long identity = Binder.clearCallingIdentity();
@@ -1956,7 +1960,7 @@
setLightBrightness(offMask, Power.BRIGHTNESS_OFF);
}
if (dimMask != 0) {
- int brightness = Power.BRIGHTNESS_DIM;
+ int brightness = mScreenBrightnessDim;
if ((newState & BATTERY_LOW_BIT) != 0 &&
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
brightness = Power.BRIGHTNESS_LOW_BATTERY;
@@ -2122,7 +2126,7 @@
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
SCREEN_BRIGHTNESS);
// Don't let applications turn the screen all the way off
- return Math.max(brightness, Power.BRIGHTNESS_DIM);
+ return Math.max(brightness, mScreenBrightnessDim);
} catch (SettingNotFoundException snfe) {
return Power.BRIGHTNESS_ON;
}
@@ -2810,7 +2814,7 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
// Don't let applications turn the screen all the way off
synchronized (mLocks) {
- brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
+ brightness = Math.max(brightness, mScreenBrightnessDim);
mLcdLight.setBrightness(brightness);
mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0);
mButtonLight.setBrightness(brightness);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2714fc5..7e28c4f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -148,7 +148,8 @@
Slog.i(TAG, "Package Manager");
pm = PackageManagerService.main(context,
- factoryTest != SystemServer.FACTORY_TEST_OFF);
+ factoryTest != SystemServer.FACTORY_TEST_OFF,
+ false);
ActivityManagerService.setSystemProcess();
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index e6b5898..883fc71 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -37,7 +37,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiWatchdogStateMachine;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.Wps;
+import android.net.wifi.WpsInfo;
import android.net.wifi.WpsResult;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
@@ -69,6 +69,7 @@
import java.io.PrintWriter;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
import com.android.server.am.BatteryStatsService;
import com.android.internal.R;
@@ -96,6 +97,7 @@
private static final int IDLE_REQUEST = 0;
private boolean mScreenOff;
private boolean mDeviceIdle;
+ private boolean mEmergencyCallbackMode = false;
private int mPluggedType;
/* Chipset supports background scan */
@@ -286,7 +288,7 @@
}
case WifiManager.CMD_START_WPS: {
//replyTo has the original source
- mWifiStateMachine.startWps(msg.replyTo, (Wps)msg.obj);
+ mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);
break;
}
case WifiManager.CMD_DISABLE_NETWORK: {
@@ -996,6 +998,9 @@
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED);
mWifiStateMachine.sendBluetoothAdapterStateChange(state);
+ } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
+ updateWifiState();
}
}
@@ -1057,7 +1062,13 @@
private void updateWifiState() {
boolean lockHeld = mLocks.hasLocks();
int strongestLockMode = WifiManager.WIFI_MODE_FULL;
- boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
+ boolean wifiShouldBeStarted;
+
+ if (mEmergencyCallbackMode) {
+ wifiShouldBeStarted = false;
+ } else {
+ wifiShouldBeStarted = !mDeviceIdle || lockHeld;
+ }
if (lockHeld) {
strongestLockMode = mLocks.getStrongestLockMode();
@@ -1097,6 +1108,7 @@
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
intentFilter.addAction(ACTION_DEVICE_IDLE);
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+ intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
mContext.registerReceiver(mReceiver, intentFilter);
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 09ddc2f..1e4faad 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -225,7 +225,7 @@
return false;
}
}
-
+
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
@@ -697,6 +697,7 @@
private void manageServicesLocked() {
populateEnabledServicesLocked(mEnabledServices);
updateServicesStateLocked(mInstalledServices, mEnabledServices);
+ disableAccessibilityIfNoEnabledServices(mEnabledServices);
}
/**
@@ -781,6 +782,19 @@
}
/**
+ * Disables accessibility if there are no enabled accessibility services which
+ * to consume the generated accessibility events.
+ *
+ * @param enabledServices The set of enabled services.
+ */
+ private void disableAccessibilityIfNoEnabledServices(Set<ComponentName> enabledServices) {
+ if (enabledServices.isEmpty()) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0);
+ }
+ }
+
+ /**
* Sends the state to the clients.
*/
private void sendStateToClientsLocked() {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index bfb244b..9ebdd52 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -71,6 +71,7 @@
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.ManifestDigest;
+import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -221,6 +222,7 @@
final Context mContext;
final boolean mFactoryTest;
+ final boolean mOnlyCore;
final boolean mNoDexOpt;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
@@ -809,8 +811,9 @@
return false;
}
- public static final IPackageManager main(Context context, boolean factoryTest) {
- PackageManagerService m = new PackageManagerService(context, factoryTest);
+ public static final IPackageManager main(Context context, boolean factoryTest,
+ boolean onlyCore) {
+ PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
ServiceManager.addService("package", m);
return m;
}
@@ -837,7 +840,7 @@
return res;
}
- public PackageManagerService(Context context, boolean factoryTest) {
+ public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
@@ -847,6 +850,7 @@
mContext = context;
mFactoryTest = factoryTest;
+ mOnlyCore = onlyCore;
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings();
@@ -1051,18 +1055,20 @@
mInstaller.moveFiles();
// Prune any system packages that no longer exist.
- Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
- while (psit.hasNext()) {
- PackageSetting ps = psit.next();
- if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
- && !mPackages.containsKey(ps.name)
- && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
- psit.remove();
- String msg = "System package " + ps.name
- + " no longer exists; wiping its data";
- reportSettingsProblem(Log.WARN, msg);
- mInstaller.remove(ps.name, 0);
- mUserManager.removePackageForAllUsers(ps.name);
+ if (!mOnlyCore) {
+ Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
+ while (psit.hasNext()) {
+ PackageSetting ps = psit.next();
+ if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
+ && !mPackages.containsKey(ps.name)
+ && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
+ psit.remove();
+ String msg = "System package " + ps.name
+ + " no longer exists; wiping its data";
+ reportSettingsProblem(Log.WARN, msg);
+ mInstaller.remove(ps.name, 0);
+ mUserManager.removePackageForAllUsers(ps.name);
+ }
}
}
@@ -1077,18 +1083,23 @@
//delete tmp files
deleteTempPackageFiles();
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
- SystemClock.uptimeMillis());
- mAppInstallObserver = new AppDirObserver(
- mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
- mAppInstallObserver.startWatching();
- scanDirLI(mAppInstallDir, 0, scanMode, 0);
-
- mDrmAppInstallObserver = new AppDirObserver(
- mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
- mDrmAppInstallObserver.startWatching();
- scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
- scanMode, 0);
+ if (!mOnlyCore) {
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
+ SystemClock.uptimeMillis());
+ mAppInstallObserver = new AppDirObserver(
+ mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
+ mAppInstallObserver.startWatching();
+ scanDirLI(mAppInstallDir, 0, scanMode, 0);
+
+ mDrmAppInstallObserver = new AppDirObserver(
+ mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
+ mDrmAppInstallObserver.startWatching();
+ scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
+ scanMode, 0);
+ } else {
+ mAppInstallObserver = null;
+ mDrmAppInstallObserver = null;
+ }
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
@@ -2749,6 +2760,7 @@
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(scanPath);
pp.setSeparateProcesses(mSeparateProcesses);
+ pp.setOnlyCoreApps(mOnlyCore);
final PackageParser.Package pkg = pp.parsePackage(scanFile,
scanPath, mMetrics, parseFlags);
if (pkg == null) {
@@ -4044,7 +4056,7 @@
+ " info=" + bp.pendingInfo);
if (bp.packageSetting == null && bp.pendingInfo != null) {
final BasePermission tree = findPermissionTreeLP(bp.name);
- if (tree != null) {
+ if (tree != null && tree.perm != null) {
bp.packageSetting = tree.packageSetting;
bp.perm = new PackageParser.Permission(tree.perm.owner,
new PermissionInfo(bp.pendingInfo));
@@ -8394,4 +8406,15 @@
mUserManager.removeUser(userId);
return true;
}
+
+ @Override
+ public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ "Only package verification agents can read the verifier device identity");
+
+ synchronized (mPackages) {
+ return mSettings.getVerifierDeviceIdentityLPw();
+ }
+ }
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index f270003..7cdb5b1 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -39,6 +39,7 @@
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
import android.content.pm.Signature;
+import android.content.pm.VerifierDeviceIdentity;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -86,7 +87,10 @@
// used to grant newer permissions one time during a system upgrade.
int mInternalSdkPlatform;
int mExternalSdkPlatform;
-
+
+ /** Device identity for the purpose of package verification. */
+ private VerifierDeviceIdentity mVerifierDeviceIdentity;
+
// The user's preferred activities associated with particular intent
// filters.
final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
@@ -865,6 +869,12 @@
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.endTag(null, "last-platform-version");
+ if (mVerifierDeviceIdentity != null) {
+ serializer.startTag(null, "verifier");
+ serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
+ serializer.endTag(null, "verifier");
+ }
+
serializer.startTag(null, "permission-trees");
for (BasePermission bp : mPermissionTrees.values()) {
writePermissionLPr(serializer, bp);
@@ -1280,6 +1290,14 @@
}
} catch (NumberFormatException e) {
}
+ } else if (tagName.equals("verifier")) {
+ final String deviceIdentity = parser.getAttributeValue(null, "device");
+ try {
+ mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
+ } catch (IllegalArgumentException e) {
+ Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
+ + e.getMessage());
+ }
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ parser.getName());
@@ -1894,6 +1912,16 @@
return PackageManagerService.FIRST_APPLICATION_UID + N;
}
+ public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() {
+ if (mVerifierDeviceIdentity == null) {
+ mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
+
+ writeLPr();
+ }
+
+ return mVerifierDeviceIdentity;
+ }
+
public PackageSetting getDisabledSystemPkgLPr(String name) {
PackageSetting ps = mDisabledSysPackages.get(name);
return ps;
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index d7bb8b3..dc6cc0d 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -53,19 +53,22 @@
void show(int dw, int dh, int layer, int color) {
if (!mDimShown) {
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
- dw + "x" + dh + ")");
+ dw + "x" + dh + " layer=" + layer + ")");
mDimShown = true;
try {
mLastDimWidth = dw;
mLastDimHeight = dh;
mDimSurface.setPosition(0, 0);
mDimSurface.setSize(dw, dh);
+ mDimSurface.setLayer(layer);
mDimSurface.show();
} catch (RuntimeException e) {
Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
}
} else if (mLastDimWidth != dw || mLastDimHeight != dh || mDimColor != color
|| mLayer != layer) {
+ if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": pos=(0,0) (" +
+ dw + "x" + dh + " layer=" + layer + ")");
mLastDimWidth = dw;
mLastDimHeight = dh;
mLayer = layer;
@@ -80,6 +83,7 @@
if (mDimShown) {
mDimShown = false;
try {
+ if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " HIDE " + mDimSurface);
mDimSurface.hide();
} catch (RuntimeException e) {
Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index df9698e..5a7fc9f 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -7458,9 +7458,12 @@
windowDetachedWallpaper = w;
}
if (w.mAnimation.getBackgroundColor() != 0) {
- windowAnimationBackground = w;
- windowAnimationBackgroundColor =
- w.mAnimation.getBackgroundColor();
+ if (windowAnimationBackground == null || w.mAnimLayer <
+ windowAnimationBackground.mAnimLayer) {
+ windowAnimationBackground = w;
+ windowAnimationBackgroundColor =
+ w.mAnimation.getBackgroundColor();
+ }
}
}
animating = true;
@@ -7469,14 +7472,18 @@
// If this window's app token is running a detached wallpaper
// animation, make a note so we can ensure the wallpaper is
// displayed behind it.
- if (w.mAppToken != null && w.mAppToken.animation != null) {
+ if (w.mAppToken != null && w.mAppToken.animation != null
+ && w.mAppToken.animating) {
if (w.mAppToken.animation.getDetachWallpaper()) {
windowDetachedWallpaper = w;
}
if (w.mAppToken.animation.getBackgroundColor() != 0) {
- windowAnimationBackground = w;
- windowAnimationBackgroundColor =
- w.mAppToken.animation.getBackgroundColor();
+ if (windowAnimationBackground == null || w.mAnimLayer <
+ windowAnimationBackground.mAnimLayer) {
+ windowAnimationBackground = w;
+ windowAnimationBackgroundColor =
+ w.mAppToken.animation.getBackgroundColor();
+ }
}
}
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index bb36d3a..0ee3f17 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -968,6 +968,7 @@
+ mPolicyVisibilityAfterAnim);
}
mPolicyVisibility = mPolicyVisibilityAfterAnim;
+ mService.mLayoutNeeded = true;
if (!mPolicyVisibility) {
if (mService.mCurrentFocus == this) {
mService.mFocusMayChange = true;
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 54bce09..1025fa8 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -35,22 +35,21 @@
while ((n = q->read(buffer, 8)) > 0) {
for (int i=0 ; i<n ; i++) {
- if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
- printf("time=%lld, value=<%5.1f,%5.1f,%5.1f>\n",
- buffer[i].timestamp,
- buffer[i].acceleration.x,
- buffer[i].acceleration.y,
- buffer[i].acceleration.z);
- }
-
+ float t;
if (oldTimeStamp) {
- float t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
- printf("%f ms (%f Hz)\n", t*1000, 1.0/t);
+ t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
} else {
- float t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
- printf("first event: %f ms\n", t*1000);
+ t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
}
oldTimeStamp = buffer[i].timestamp;
+
+ if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+ printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+ buffer[i].timestamp,
+ buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
+ 1.0/t);
+ }
+
}
}
if (n<0 && n != -EAGAIN) {
@@ -79,7 +78,7 @@
q->enableSensor(accelerometer);
- q->setEventRate(accelerometer, ms2ns(200));
+ q->setEventRate(accelerometer, ms2ns(10));
sp<Looper> loop = new Looper(false);
loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_extended b/services/tests/servicestests/res/raw/xt_qtaguid_extended
index 5bef3dd..2f3b4ec 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_extended
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_extended
@@ -1,3 +1,3 @@
-acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats
-0x0 1000 test0 1024 10 2048 20 2716057
-0x0000F00D00000000 1000 test0 512 5 512 5 3370318
+acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats idx
+0x0 1000 test0 1024 10 2048 20 2716057 2
+0x0000F00D00000000 1000 test0 512 5 512 5 3370318 3
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical b/services/tests/servicestests/res/raw/xt_qtaguid_typical
index 7c4f04e..8df4b1b 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical
@@ -1,32 +1,32 @@
idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
-1 wlan0 0x0 0 14615 4270
-2 wlan0 0x0 1000 5175 915
-3 wlan0 0x0 1021 3381 903
-4 wlan0 0x0 10004 333821 53558
-5 wlan0 0x0 10010 4888 37363
-6 wlan0 0x0 10013 52 104
-7 wlan0 0x74182ada00000000 10004 18725 1066
-8 rmnet0 0x0 0 301274 30244
-9 rmnet0 0x0 1000 304 441
-10 rmnet0 0x0 1013 2880 2272
-11 rmnet0 0x0 1021 31407 8430
-12 rmnet0 0x0 10003 32665 3814
-13 rmnet0 0x0 10004 2373141 420112
-14 rmnet0 0x0 10010 870370 1111727
-15 rmnet0 0x0 10013 240 240
-16 rmnet0 0x0 10016 16703 13512
-17 rmnet0 0x0 10017 3990 3269
-18 rmnet0 0x0 10018 474504 14516062
-19 rmnet0 0x0 10019 782804 71077
-20 rmnet0 0x0 10022 70671 49684
-21 rmnet0 0x0 10029 5785354 397159
-22 rmnet0 0x0 10033 2102 1686
-23 rmnet0 0x0 10034 15495464 227694
-24 rmnet0 0x0 10037 31184994 684122
-25 rmnet0 0x0 10051 298687 113485
-26 rmnet0 0x0 10056 29504 20669
-27 rmnet0 0x0 10069 683 596
-28 rmnet0 0x0 10072 34051 12453
-29 rmnet0 0x0 10077 7025393 213866
-30 rmnet0 0x0 10081 354 1178
-31 rmnet0 0x74182ada00000000 10037 28507378 437004
+2 wlan0 0x0 0 14615 4270
+3 wlan0 0x0 1000 5175 915
+4 wlan0 0x0 1021 3381 903
+5 wlan0 0x0 10004 333821 53558
+6 wlan0 0x0 10010 4888 37363
+7 wlan0 0x0 10013 52 104
+8 wlan0 0x74182ada00000000 10004 18725 1066
+9 rmnet0 0x0 0 301274 30244
+10 rmnet0 0x0 1000 304 441
+11 rmnet0 0x0 1013 2880 2272
+12 rmnet0 0x0 1021 31407 8430
+13 rmnet0 0x0 10003 32665 3814
+14 rmnet0 0x0 10004 2373141 420112
+15 rmnet0 0x0 10010 870370 1111727
+16 rmnet0 0x0 10013 240 240
+17 rmnet0 0x0 10016 16703 13512
+18 rmnet0 0x0 10017 3990 3269
+19 rmnet0 0x0 10018 474504 14516062
+20 rmnet0 0x0 10019 782804 71077
+21 rmnet0 0x0 10022 70671 49684
+22 rmnet0 0x0 10029 5785354 397159
+23 rmnet0 0x0 10033 2102 1686
+24 rmnet0 0x0 10034 15495464 227694
+25 rmnet0 0x0 10037 31184994 684122
+26 rmnet0 0x0 10051 298687 113485
+27 rmnet0 0x0 10056 29504 20669
+28 rmnet0 0x0 10069 683 596
+29 rmnet0 0x0 10072 34051 12453
+30 rmnet0 0x0 10077 7025393 213866
+31 rmnet0 0x0 10081 354 1178
+32 rmnet0 0x74182ada00000000 10037 28507378 437004
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set b/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
index 3678b10..f9f34ac 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
@@ -1,13 +1,13 @@
idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_packets rx_tcp_bytes rx_udp_packets rx_udp_bytes rx_other_packets rx_other_bytes tx_tcp_packets tx_tcp_bytes tx_udp_packets tx_udp_bytes tx_other_packets tx_other_bytes
-1 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0
-1 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-2 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0
-2 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0
-3 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0
-3 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0
-4 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0
-5 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0
-6 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+2 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0
+3 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+4 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0
+5 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0
+6 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0
+7 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+8 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0
+9 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+10 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0
+11 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+12 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0
+13 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 51922da..e898aac 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1547,6 +1547,32 @@
}
/**
+ * Checks if a given number is an emergency number for a specific country.
+ *
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @return if the number is an emergency number for the specific country, then return true,
+ * otherwise false
+ * @hide
+ */
+ public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ try {
+ PhoneNumber pn = util.parse(number, defaultCountryIso);
+ // libphonenumber guarantees short numbers such as emergency numbers are classified as
+ // invalid. Therefore, if the number passes the validation test, we believe it is not an
+ // emergency number.
+ // TODO: Compare against a list of country-specific known emergency numbers instead, once
+ // that has been collected.
+ if (util.isValidNumber(pn)) {
+ return false;
+ }
+ } catch (NumberParseException e) {
+ }
+ return isEmergencyNumber(number);
+ }
+
+ /**
* isVoiceMailNumber: checks a given number against the voicemail
* number provided by the RIL and SIM card. The caller must have
* the READ_PHONE_STATE credential.
diff --git a/telephony/java/com/android/internal/telephony/ApnSetting.java b/telephony/java/com/android/internal/telephony/ApnSetting.java
old mode 100644
new mode 100755
index b88bcf7..002ffad9
--- a/telephony/java/com/android/internal/telephony/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/ApnSetting.java
@@ -38,12 +38,24 @@
public final String numeric;
public final String protocol;
public final String roamingProtocol;
+ /**
+ * Current status of APN
+ * true : enabled APN, false : disabled APN.
+ */
+ public final boolean carrierEnabled;
+ /**
+ * Radio Access Technology info
+ * To check what values can hold, refer to ServiceState.java.
+ * This should be spread to other technologies,
+ * but currently only used for LTE(14) and EHRPD(13).
+ */
+ public final int bearer;
public ApnSetting(int id, String numeric, String carrier, String apn,
String proxy, String port,
String mmsc, String mmsProxy, String mmsPort,
String user, String password, int authType, String[] types,
- String protocol, String roamingProtocol) {
+ String protocol, String roamingProtocol, boolean carrierEnabled, int bearer) {
this.id = id;
this.numeric = numeric;
this.carrier = carrier;
@@ -59,6 +71,8 @@
this.types = types;
this.protocol = protocol;
this.roamingProtocol = roamingProtocol;
+ this.carrierEnabled = carrierEnabled;
+ this.bearer = bearer;
}
/**
@@ -76,8 +90,8 @@
*
* v2 format:
* [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <mmsc>, <mmsproxy>,
- * <mmsport>, <user>, <password, <authtype>, <mcc>, <mnc>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>
+ * <mmsport>, <user>, <password>, <authtype>, <mcc>, <mnc>,
+ * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearer>
*
* Note that the strings generated by toString() do not contain the username
* and password and thus cannot be read by this method.
@@ -110,22 +124,32 @@
String[] typeArray;
String protocol, roamingProtocol;
+ boolean carrierEnabled;
+ int bearer;
if (version == 1) {
typeArray = new String[a.length - 13];
System.arraycopy(a, 13, typeArray, 0, a.length - 13);
protocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
+ carrierEnabled = true;
+ bearer = 0;
} else {
- if (a.length < 16) {
+ if (a.length < 18) {
return null;
}
typeArray = a[13].split("\\s*\\|\\s*");
protocol = a[14];
roamingProtocol = a[15];
+ try {
+ carrierEnabled = Boolean.parseBoolean(a[16]);
+ } catch (Exception e) {
+ carrierEnabled = true;
+ }
+ bearer = Integer.parseInt(a[17]);
}
return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
- a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol);
+ a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol,carrierEnabled,bearer);
}
public String toString() {
@@ -149,6 +173,8 @@
}
sb.append(", ").append(protocol);
sb.append(", ").append(roamingProtocol);
+ sb.append(", ").append(carrierEnabled);
+ sb.append(", ").append(bearer);
return sb.toString();
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 25f8c8b..7c37a65 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -254,7 +254,9 @@
// Change the callerInfo number ONLY if it is an emergency number
// or if it is the voicemail number. If it is either, take a
// shortcut and skip the query.
- if (PhoneNumberUtils.isEmergencyNumber(number)) {
+ Locale locale = context.getResources().getConfiguration().locale;
+ String countryIso = getCurrentCountryIso(context, locale);
+ if (PhoneNumberUtils.isEmergencyNumber(number, countryIso)) {
return new CallerInfo().markAsEmergency(context);
} else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
return new CallerInfo().markAsVoiceMail();
@@ -514,18 +516,8 @@
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();
- String countryIso;
Locale locale = context.getResources().getConfiguration().locale;
- CountryDetector detector = (CountryDetector) context.getSystemService(
- Context.COUNTRY_DETECTOR);
- if (detector != null) {
- countryIso = detector.detectCountry().getCountryIso();
- } else {
- countryIso = locale.getCountry();
- Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
- + countryIso);
- }
-
+ String countryIso = getCurrentCountryIso(context, locale);
PhoneNumber pn = null;
try {
if (VDBG) Log.v(TAG, "parsing '" + number
@@ -546,6 +538,24 @@
}
/**
+ * @return The ISO 3166-1 two letters country code of the country the user
+ * is in.
+ */
+ private static String getCurrentCountryIso(Context context, Locale locale) {
+ String countryIso;
+ CountryDetector detector = (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (detector != null) {
+ countryIso = detector.detectCountry().getCountryIso();
+ } else {
+ countryIso = locale.getCountry();
+ Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
+ + countryIso);
+ }
+ return countryIso;
+ }
+
+ /**
* @return a string debug representation of this instance.
*/
public String toString() {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 2e8a742..17734ca 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -403,7 +403,9 @@
cw.number = number;
// check to see if these are recognized numbers, and use shortcuts if we can.
- if (PhoneNumberUtils.isEmergencyNumber(number)) {
+ CountryDetector detector = (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (PhoneNumberUtils.isEmergencyNumber(number, detector.detectCountry().getCountryIso())) {
cw.event = EVENT_EMERGENCY_NUMBER;
} else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
cw.event = EVENT_VOICEMAIL_NUMBER;
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 5e64148..444f0d2 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -932,7 +932,8 @@
boolean getCallForwardingIndicator();
/**
- * Get the line 1 phone number (MSISDN).<p>
+ * Get the line 1 phone number (MSISDN). For CDMA phones, the MDN is returned
+ * and {@link #getMsisdn()} will return the MSISDN on CDMA/LTE phones.<p>
*
* @return phone number. May return null if not
* available or the SIM is not ready
@@ -1432,6 +1433,13 @@
String getMeid();
/**
+ * Retrieves the MSISDN from the UICC. For GSM/UMTS phones, this is equivalent to
+ * {@link #getLine1Number()}. For CDMA phones, {@link #getLine1Number()} returns
+ * the MDN, so this method is provided to return the MSISDN on CDMA/LTE phones.
+ */
+ String getMsisdn();
+
+ /**
* Retrieves IMEI for phones. Returns null if IMEI is not set.
*/
String getImei();
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 4f86ea8..82f3955 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -1124,6 +1124,11 @@
Log.e(LOG_TAG, "requestIsimAuthentication() is only supported on LTE devices");
}
+ public String getMsisdn() {
+ logUnexpectedGsmMethodCall("getMsisdn");
+ return null;
+ }
+
/**
* Common error logger method for unexpected calls to CDMA-only methods.
*/
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 3678017..e0e8d49 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -686,6 +686,10 @@
return mActivePhone.getMeid();
}
+ public String getMsisdn() {
+ return mActivePhone.getMsisdn();
+ }
+
public String getImei() {
return mActivePhone.getImei();
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index f4ed91d..6903025 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -141,6 +141,11 @@
}
@Override
+ public String getMsisdn() {
+ return mIccRecords.getMsisdnNumber();
+ }
+
+ @Override
public void requestIsimAuthentication(String nonce, Message result) {
mCM.requestIsimAuthentication(nonce, result);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index a728d0a..078e51d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -338,7 +338,7 @@
apnId = mDefaultApnId;
}
mActiveApn = new ApnSetting(apnId, "", "", "", "", "", "", "", "", "",
- "", 0, types, "IP", "IP");
+ "", 0, types, "IP", "IP", true, 0);
if (DBG) log("call conn.bringUp mActiveApn=" + mActiveApn);
Message msg = obtainMessage();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
index c4fa6f6..0617fee 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -19,6 +19,7 @@
import android.os.SystemProperties;
import android.util.Log;
+import com.android.internal.telephony.AdnRecordLoader;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.IccCardApplication.AppType;
import com.android.internal.telephony.IccFileHandler;
@@ -276,6 +277,10 @@
obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
recordsToLoad++;
+ new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
+ obtainMessage(EVENT_GET_MSISDN_DONE));
+ recordsToLoad++;
+
iccFh.loadEFTransparent(EF_CSIM_LI,
obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
recordsToLoad++;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 1db9860..d325aaa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -877,6 +877,11 @@
return mIccRecords.getMsisdnNumber();
}
+ @Override
+ public String getMsisdn() {
+ return mIccRecords.getMsisdnNumber();
+ }
+
public String getLine1AlphaTag() {
return mIccRecords.getMsisdnAlphaTag();
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 4e43fcd..6d0b696 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -115,7 +115,6 @@
static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
static final String APN_ID = "apn_id";
private boolean canSetPreferApn = false;
- private boolean mRadioAvailable = false;
@Override
protected void onActionIntentReconnectAlarm(Intent intent) {
@@ -890,7 +889,10 @@
types,
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.ROAMING_PROTOCOL)));
+ Telephony.Carriers.ROAMING_PROTOCOL)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.CARRIER_ENABLED)) == 1,
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)));
result.add(apn);
} while (cursor.moveToNext());
}
@@ -1572,7 +1574,7 @@
private void onRecordsLoaded() {
if (DBG) log("onRecordsLoaded: createAllApnList");
createAllApnList();
- if (mRadioAvailable) {
+ if (mPhone.mCM.getRadioState().isOn()) {
if (DBG) log("onRecordsLoaded: notifying data availability");
notifyDataAvailability(Phone.REASON_SIM_LOADED);
}
@@ -1706,7 +1708,6 @@
@Override
protected void onRadioAvailable() {
if (DBG) log("onRadioAvailable");
- mRadioAvailable = true;
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
// FIXME this can be improved
@@ -1734,7 +1735,6 @@
dc.resetRetryCount();
}
mReregisterOnReconnectFailure = false;
- mRadioAvailable = false;
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
@@ -1985,6 +1985,9 @@
String operator = mPhone.mIccRecords.getOperatorNumeric();
if (operator != null) {
String selection = "numeric = '" + operator + "'";
+ // query only enabled apn.
+ // carrier_enabled : 1 means enabled apn, 0 disabled apn.
+ selection += " and carrier_enabled = 1";
if (DBG) log("createAllApnList: selection=" + selection);
Cursor cursor = mPhone.getContext().getContentResolver().query(
@@ -2072,6 +2075,18 @@
}
/**
+ * Check current radio access technology is LTE or EHRPD.
+ *
+ * @param integer value of radio access technology
+ * @return true when current radio access technology is LTE or EHRPD
+ * @ false when current radio access technology is not LTE or EHRPD
+ */
+ private boolean needToCheckApnBearer(int radioTech) {
+ return (radioTech == ServiceState.RADIO_TECHNOLOGY_LTE ||
+ radioTech == ServiceState.RADIO_TECHNOLOGY_EHRPD);
+ }
+
+ /**
* Build a list of APNs to be used to create PDP's.
*
* @param requestedApnType
@@ -2091,6 +2106,9 @@
}
String operator = mPhone.mIccRecords.getOperatorNumeric();
+ int radioTech = mPhone.getServiceState().getRadioTechnology();
+ boolean needToCheckApnBearer = needToCheckApnBearer(radioTech);
+
if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
if (canSetPreferApn && mPreferredApn != null) {
if (DBG) {
@@ -2098,9 +2116,15 @@
+ mPreferredApn.numeric + ":" + mPreferredApn);
}
if (mPreferredApn.numeric.equals(operator)) {
- apnList.add(mPreferredApn);
- if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
- return apnList;
+ if (!needToCheckApnBearer || mPreferredApn.bearer == radioTech) {
+ apnList.add(mPreferredApn);
+ if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
+ return apnList;
+ } else {
+ if (DBG) log("buildWaitingApns: no preferred APN");
+ setPreferredApn(-1);
+ mPreferredApn = null;
+ }
} else {
if (DBG) log("buildWaitingApns: no preferred APN");
setPreferredApn(-1);
@@ -2111,7 +2135,10 @@
if (mAllApns != null) {
for (ApnSetting apn : mAllApns) {
if (apn.canHandleType(requestedApnType)) {
- apnList.add(apn);
+ if (!needToCheckApnBearer || apn.bearer == radioTech) {
+ if (DBG) log("apn info : " +apn.toString());
+ apnList.add(apn);
+ }
}
}
} else {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index d84715e..73c319c 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -127,7 +127,7 @@
private static final int EVENT_GET_MWIS_DONE = 7;
private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
- private static final int EVENT_GET_MSISDN_DONE = 10;
+ protected static final int EVENT_GET_MSISDN_DONE = 10;
private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
private static final int EVENT_GET_SPN_DONE = 12;
private static final int EVENT_GET_SPDI_DONE = 13;
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
old mode 100644
new mode 100755
index 1032074..ac8c4c16
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
@@ -44,6 +44,8 @@
for (i = 0; i < a1.types.length; i++) {
assertEquals(a1.types[i], a2.types[i]);
}
+ assertEquals(a1.carrierEnabled, a2.carrierEnabled);
+ assertEquals(a1.bearer, a2.bearer);
}
@SmallTest
@@ -58,21 +60,21 @@
testString = "Vodafone IT,web.omnitel.it,,,,,,,,,222,10,,DUN";
expected_apn = new ApnSetting(
-1, "22210", "Vodafone IT", "web.omnitel.it", "", "",
- "", "", "", "", "", 0, dunTypes, "IP", "IP");
+ "", "", "", "", "", 0, dunTypes, "IP", "IP",true,0);
assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
// A v2 string.
- testString = "[ApnSettingV2] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP";
+ testString = "[ApnSettingV2] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,14";
expected_apn = new ApnSetting(
-1, "12345", "Name", "apn", "", "",
- "", "", "", "", "", 0, mmsTypes, "IPV6", "IP");
+ "", "", "", "", "", 0, mmsTypes, "IPV6", "IP",true,14);
assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
// A v2 string with spaces.
- testString = "[ApnSettingV2] Name,apn, ,,,,,,,,123,45,,mms|*,IPV4V6, IP";
+ testString = "[ApnSettingV2] Name,apn, ,,,,,,,,123,45,,mms|*,IPV4V6, IP,true,14";
expected_apn = new ApnSetting(
-1, "12345", "Name", "apn", "", "",
- "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP");
+ "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP",true,14);
assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
// Return null if insufficient fields given.
@@ -83,11 +85,11 @@
assertEquals(null, ApnSetting.fromString(testString));
// Parse (incorrect) V2 format without the tag as V1.
- testString = "Name,apn,,,,,,,,,123, 45,,mms|*,IPV6";
+ testString = "Name,apn,,,,,,,,,123, 45,,mms|*,IPV6,true,14";
String[] incorrectTypes = {"mms|*", "IPV6"};
expected_apn = new ApnSetting(
-1, "12345", "Name", "apn", "", "",
- "", "", "", "", "", 0, incorrectTypes, "IP", "IP");
+ "", "", "", "", "", 0, incorrectTypes, "IP", "IP",true,14);
assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
}
@@ -98,11 +100,10 @@
ApnSetting apn = new ApnSetting(
99, "12345", "Name", "apn", "proxy", "port",
"mmsc", "mmsproxy", "mmsport", "user", "password", 0,
- types, "IPV4V6", "IP");
+ types, "IPV4V6", "IP", true, 14);
String expected = "[ApnSettingV2] Name, 99, 12345, apn, proxy, " +
"mmsc, mmsproxy, mmsport, port, 0, default | *, " +
- "IPV4V6, IP";
+ "IPV4V6, IP, true, 14";
assertEquals(expected, apn.toString());
}
}
-
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 6e9d0f9d..d3e4b78 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -536,4 +536,20 @@
// The given number was formatted.
assertEquals("650-291-0000", PhoneNumberUtils.formatNumber("650-291-0000", null, "US"));
}
+ @SmallTest
+ public void testIsEmergencyNumber() {
+ assertTrue(PhoneNumberUtils.isEmergencyNumber("911", "US"));
+ assertTrue(PhoneNumberUtils.isEmergencyNumber("112", "US"));
+ // The next two numbers are not valid phone numbers in the US, but can be used to trick the
+ // system to dial 911 and 112, which are emergency numbers in the US. For the purpose of
+ // addressing that, they are also classified as emergency numbers in the US.
+ assertTrue(PhoneNumberUtils.isEmergencyNumber("91112345", "US"));
+ assertTrue(PhoneNumberUtils.isEmergencyNumber("11212345", "US"));
+ // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
+ // in Singapore, as 911 is not an emergency number there.
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234", "SG"));
+ // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
+ // in Brazil, as 112 is not an emergency number there.
+ assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567", "BR"));
+ }
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 501c219..f2fb36f 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -38,6 +38,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.pm.ManifestDigest;
+import android.content.pm.VerifierDeviceIdentity;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -552,4 +553,12 @@
public void verifyPendingInstall(int id, boolean verified, String failureMessage) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public VerifierDeviceIdentity getVerifierDeviceIdentity() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
index 45eea5e..86479d5 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
@@ -2,29 +2,26 @@
#include "ip.rsh"
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
- float4 *output = (float4 *)v_out;
+void root(float4 *out, const void *usrData, uint32_t x, uint32_t y) {
const FilterStruct *fs = (const FilterStruct *)usrData;
- const float4 *input = (const float4 *)rsGetElementAt(fs->ain, 0, y);
-
float3 blurredPixel = 0;
const float *gPtr = fs->gaussian;
if ((x > fs->radius) && (x < (fs->width - fs->radius))) {
- const float4 *i = input + (x - fs->radius);
for (int r = -fs->radius; r <= fs->radius; r ++) {
+ const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x + r, y);
blurredPixel += i->xyz * gPtr[0];
gPtr++;
- i++;
}
} else {
for (int r = -fs->radius; r <= fs->radius; r ++) {
// Stepping left and right away from the pixel
- int validW = rsClamp((int)x + r, (int)0, (int)(fs->width - 1));
- blurredPixel += input[validW].xyz * gPtr[0];
+ int validX = rsClamp((int)x + r, (int)0, (int)(fs->width - 1));
+ const float4 *i = (const float4 *)rsGetElementAt(fs->ain, validX, y);
+ blurredPixel += i->xyz * gPtr[0];
gPtr++;
}
}
- output->xyz = blurredPixel;
+ out->xyz = blurredPixel;
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index 6b0cde0..8b07bc2 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -55,27 +55,20 @@
gamma = (float3)g;
}
-//sliao
-extern uchar3 __attribute__((overloadable)) convert2uchar3(float3 xyz);
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
- uchar4 *output = (uchar4 *)v_out;
+void root(uchar4 *out, const void *usrData, uint32_t x, uint32_t y) {
const FilterStruct *fs = (const FilterStruct *)usrData;
- const float4 *input = (const float4 *)rsGetElementAt(fs->ain, x, 0);
-
float3 blurredPixel = 0;
const float *gPtr = fs->gaussian;
if ((y > fs->radius) && (y < (fs->height - fs->radius))) {
- const float4 *i = input + ((y - fs->radius) * fs->width);
for (int r = -fs->radius; r <= fs->radius; r ++) {
+ const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x, y + r);
blurredPixel += i->xyz * gPtr[0];
gPtr++;
- i += fs->width;
}
} else {
for (int r = -fs->radius; r <= fs->radius; r ++) {
int validH = rsClamp((int)y + r, (int)0, (int)(fs->height - 1));
- const float4 *i = input + validH * fs->width;
+ const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x, validH);
blurredPixel += i->xyz * gPtr[0];
gPtr++;
}
@@ -87,7 +80,7 @@
temp = pow(temp, (float3)gamma);
temp = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
- output->xyz = convert_uchar3(temp);
+ out->xyz = convert_uchar3(temp);
//output->w = input->w;
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
index 8cad82b..aae29a4 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
@@ -37,162 +37,6 @@
volatile uchar3 uc3;
volatile uchar4 uc4;
-#define TEST_FN_FUNC_FN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1); \
- f2 = fnc(f2); \
- f3 = fnc(f3); \
- f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, (float*) &f1); \
- f2 = fnc(f2, (float2*) &f2); \
- f3 = fnc(f3, (float3*) &f3); \
- f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, f1); \
- f2 = fnc(f2, f2); \
- f3 = fnc(f3, f3); \
- f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, f1); \
- f2 = fnc(f2, f1); \
- f3 = fnc(f3, f1); \
- f4 = fnc(f4, f1);
-
-#define TEST_FN_FUNC_FN_IN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, i1); \
- f2 = fnc(f2, i2); \
- f3 = fnc(f3, i3); \
- f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, i1); \
- f2 = fnc(f2, i1); \
- f3 = fnc(f3, i1); \
- f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, f1, f1); \
- f2 = fnc(f2, f2, f2); \
- f3 = fnc(f3, f3, f3); \
- f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_PIN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, (int*) &i1); \
- f2 = fnc(f2, (int2*) &i2); \
- f3 = fnc(f3, (int3*) &i3); \
- f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- f1 = fnc(f1, f1, (int*) &i1); \
- f2 = fnc(f2, f2, (int2*) &i2); \
- f3 = fnc(f3, f3, (int3*) &i3); \
- f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc) \
- rsDebug("Testing " #fnc, 0); \
- i1 = fnc(f1); \
- i2 = fnc(f2); \
- i3 = fnc(f3); \
- i4 = fnc(f4);
-
-
-static bool test_fp_math(uint32_t index) {
- bool failed = false;
- start();
-
- TEST_FN_FUNC_FN(acos);
- TEST_FN_FUNC_FN(acosh);
- TEST_FN_FUNC_FN(acospi);
- TEST_FN_FUNC_FN(asin);
- TEST_FN_FUNC_FN(asinh);
- TEST_FN_FUNC_FN(asinpi);
- TEST_FN_FUNC_FN(atan);
- TEST_FN_FUNC_FN_FN(atan2);
- TEST_FN_FUNC_FN(atanh);
- TEST_FN_FUNC_FN(atanpi);
- TEST_FN_FUNC_FN_FN(atan2pi);
- TEST_FN_FUNC_FN(cbrt);
- TEST_FN_FUNC_FN(ceil);
- TEST_FN_FUNC_FN_FN(copysign);
- TEST_FN_FUNC_FN(cos);
- TEST_FN_FUNC_FN(cosh);
- TEST_FN_FUNC_FN(cospi);
- TEST_FN_FUNC_FN(erfc);
- TEST_FN_FUNC_FN(erf);
- TEST_FN_FUNC_FN(exp);
- TEST_FN_FUNC_FN(exp2);
- TEST_FN_FUNC_FN(exp10);
- TEST_FN_FUNC_FN(expm1);
- TEST_FN_FUNC_FN(fabs);
- TEST_FN_FUNC_FN_FN(fdim);
- TEST_FN_FUNC_FN(floor);
- TEST_FN_FUNC_FN_FN_FN(fma);
- TEST_FN_FUNC_FN_FN(fmax);
- TEST_FN_FUNC_FN_F(fmax);
- TEST_FN_FUNC_FN_FN(fmin);
- TEST_FN_FUNC_FN_F(fmin);
- TEST_FN_FUNC_FN_FN(fmod);
- TEST_FN_FUNC_FN_PFN(fract);
- TEST_FN_FUNC_FN_PIN(frexp);
- TEST_FN_FUNC_FN_FN(hypot);
- TEST_IN_FUNC_FN(ilogb);
- TEST_FN_FUNC_FN_IN(ldexp);
- TEST_FN_FUNC_FN_I(ldexp);
- TEST_FN_FUNC_FN(lgamma);
- TEST_FN_FUNC_FN_PIN(lgamma);
- TEST_FN_FUNC_FN(log);
- TEST_FN_FUNC_FN(log2);
- TEST_FN_FUNC_FN(log10);
- TEST_FN_FUNC_FN(log1p);
- TEST_FN_FUNC_FN(logb);
- TEST_FN_FUNC_FN_FN_FN(mad);
- TEST_FN_FUNC_FN_PFN(modf);
- // nan
- TEST_FN_FUNC_FN_FN(nextafter);
- TEST_FN_FUNC_FN_FN(pow);
- TEST_FN_FUNC_FN_IN(pown);
- TEST_FN_FUNC_FN_FN(powr);
- TEST_FN_FUNC_FN_FN(remainder);
- TEST_FN_FUNC_FN_FN_PIN(remquo);
- TEST_FN_FUNC_FN(rint);
- TEST_FN_FUNC_FN_IN(rootn);
- TEST_FN_FUNC_FN(round);
- TEST_FN_FUNC_FN(rsqrt);
- TEST_FN_FUNC_FN(sin);
- TEST_FN_FUNC_FN_PFN(sincos);
- TEST_FN_FUNC_FN(sinh);
- TEST_FN_FUNC_FN(sinpi);
- TEST_FN_FUNC_FN(sqrt);
- TEST_FN_FUNC_FN(tan);
- TEST_FN_FUNC_FN(tanh);
- TEST_FN_FUNC_FN(tanpi);
- TEST_FN_FUNC_FN(tgamma);
- TEST_FN_FUNC_FN(trunc);
-
- float time = end(index);
-
- if (failed) {
- rsDebug("test_fp_math FAILED", time);
- }
- else {
- rsDebug("test_fp_math PASSED", time);
- }
-
- return failed;
-}
-
#define DECL_INT(prefix) \
volatile char prefix##_c_1 = 1; \
volatile char2 prefix##_c_2 = 1; \
@@ -221,6 +65,10 @@
volatile long prefix##_l_1 = 1; \
volatile ulong prefix##_ul_1 = 1;
+DECL_INT(res)
+DECL_INT(src1)
+DECL_INT(src2)
+
#define TEST_INT_OP_TYPE(op, type) \
rsDebug("Testing " #op " for " #type "1", i++); \
res_##type##_1 = src1_##type##_1 op src2_##type##_1; \
@@ -243,9 +91,274 @@
rsDebug("Testing " #op " for ul1", i++); \
res_ul_1 = src1_ul_1 op src2_ul_1;
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
+#define TEST_XN_FUNC_YN(typeout, fnc, typein) \
+ res_##typeout##_1 = fnc(src1_##typein##_1); \
+ res_##typeout##_2 = fnc(src1_##typein##_2); \
+ res_##typeout##_3 = fnc(src1_##typein##_3); \
+ res_##typeout##_4 = fnc(src1_##typein##_4);
+
+#define TEST_XN_FUNC_XN_XN(type, fnc) \
+ res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1); \
+ res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2); \
+ res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3); \
+ res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4);
+
+#define TEST_X_FUNC_X_X_X(type, fnc) \
+ res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src2_##type##_1);
+
+#define TEST_IN_FUNC_IN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ TEST_XN_FUNC_YN(uc, fnc, uc) \
+ TEST_XN_FUNC_YN(c, fnc, c) \
+ TEST_XN_FUNC_YN(us, fnc, us) \
+ TEST_XN_FUNC_YN(s, fnc, s) \
+ TEST_XN_FUNC_YN(ui, fnc, ui) \
+ TEST_XN_FUNC_YN(i, fnc, i)
+
+#define TEST_UIN_FUNC_IN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ TEST_XN_FUNC_YN(uc, fnc, c) \
+ TEST_XN_FUNC_YN(us, fnc, s) \
+ TEST_XN_FUNC_YN(ui, fnc, i) \
+
+#define TEST_IN_FUNC_IN_IN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ TEST_XN_FUNC_XN_XN(uc, fnc) \
+ TEST_XN_FUNC_XN_XN(c, fnc) \
+ TEST_XN_FUNC_XN_XN(us, fnc) \
+ TEST_XN_FUNC_XN_XN(s, fnc) \
+ TEST_XN_FUNC_XN_XN(ui, fnc) \
+ TEST_XN_FUNC_XN_XN(i, fnc)
+
+#define TEST_I_FUNC_I_I_I(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ TEST_X_FUNC_X_X_X(uc, fnc) \
+ TEST_X_FUNC_X_X_X(c, fnc) \
+ TEST_X_FUNC_X_X_X(us, fnc) \
+ TEST_X_FUNC_X_X_X(s, fnc) \
+ TEST_X_FUNC_X_X_X(ui, fnc) \
+ TEST_X_FUNC_X_X_X(i, fnc)
+
+#define TEST_FN_FUNC_FN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1); \
+ f2 = fnc(f2); \
+ f3 = fnc(f3); \
+ f4 = fnc(f4);
+
+#define TEST_FN_FUNC_FN_PFN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, (float*) &f1); \
+ f2 = fnc(f2, (float2*) &f2); \
+ f3 = fnc(f3, (float3*) &f3); \
+ f4 = fnc(f4, (float4*) &f4);
+
+#define TEST_FN_FUNC_FN_FN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, f1); \
+ f2 = fnc(f2, f2); \
+ f3 = fnc(f3, f3); \
+ f4 = fnc(f4, f4);
+
+#define TEST_F34_FUNC_F34_F34(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f3 = fnc(f3, f3); \
+ f4 = fnc(f4, f4);
+
+#define TEST_FN_FUNC_FN_F(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, f1); \
+ f2 = fnc(f2, f1); \
+ f3 = fnc(f3, f1); \
+ f4 = fnc(f4, f1);
+
+#define TEST_F_FUNC_FN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1); \
+ f1 = fnc(f2); \
+ f1 = fnc(f3); \
+ f1 = fnc(f4);
+
+#define TEST_F_FUNC_FN_FN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, f1); \
+ f1 = fnc(f2, f2); \
+ f1 = fnc(f3, f3); \
+ f1 = fnc(f4, f4);
+
+#define TEST_FN_FUNC_FN_IN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, i1); \
+ f2 = fnc(f2, i2); \
+ f3 = fnc(f3, i3); \
+ f4 = fnc(f4, i4);
+
+#define TEST_FN_FUNC_FN_I(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, i1); \
+ f2 = fnc(f2, i1); \
+ f3 = fnc(f3, i1); \
+ f4 = fnc(f4, i1);
+
+#define TEST_FN_FUNC_FN_FN_FN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, f1, f1); \
+ f2 = fnc(f2, f2, f2); \
+ f3 = fnc(f3, f3, f3); \
+ f4 = fnc(f4, f4, f4);
+
+#define TEST_FN_FUNC_FN_FN_F(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, f1, f1); \
+ f2 = fnc(f2, f1, f1); \
+ f3 = fnc(f3, f1, f1); \
+ f4 = fnc(f4, f1, f1);
+
+#define TEST_FN_FUNC_FN_PIN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, (int*) &i1); \
+ f2 = fnc(f2, (int2*) &i2); \
+ f3 = fnc(f3, (int3*) &i3); \
+ f4 = fnc(f4, (int4*) &i4);
+
+#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ f1 = fnc(f1, f1, (int*) &i1); \
+ f2 = fnc(f2, f2, (int2*) &i2); \
+ f3 = fnc(f3, f3, (int3*) &i3); \
+ f4 = fnc(f4, f4, (int4*) &i4);
+
+#define TEST_IN_FUNC_FN(fnc) \
+ rsDebug("Testing " #fnc, 0); \
+ i1 = fnc(f1); \
+ i2 = fnc(f2); \
+ i3 = fnc(f3); \
+ i4 = fnc(f4);
+
+static bool test_fp_math(uint32_t index) {
+ bool failed = false;
+ start();
+
+ TEST_FN_FUNC_FN(acos);
+ TEST_FN_FUNC_FN(acosh);
+ TEST_FN_FUNC_FN(acospi);
+ TEST_FN_FUNC_FN(asin);
+ TEST_FN_FUNC_FN(asinh);
+ TEST_FN_FUNC_FN(asinpi);
+ TEST_FN_FUNC_FN(atan);
+ TEST_FN_FUNC_FN_FN(atan2);
+ TEST_FN_FUNC_FN(atanh);
+ TEST_FN_FUNC_FN(atanpi);
+ TEST_FN_FUNC_FN_FN(atan2pi);
+ TEST_FN_FUNC_FN(cbrt);
+ TEST_FN_FUNC_FN(ceil);
+ TEST_FN_FUNC_FN_FN_FN(clamp);
+ TEST_FN_FUNC_FN_FN_F(clamp);
+ TEST_FN_FUNC_FN_FN(copysign);
+ TEST_FN_FUNC_FN(cos);
+ TEST_FN_FUNC_FN(cosh);
+ TEST_FN_FUNC_FN(cospi);
+ TEST_F34_FUNC_F34_F34(cross);
+ TEST_FN_FUNC_FN(degrees);
+ TEST_F_FUNC_FN_FN(distance);
+ TEST_F_FUNC_FN_FN(dot);
+ TEST_FN_FUNC_FN(erfc);
+ TEST_FN_FUNC_FN(erf);
+ TEST_FN_FUNC_FN(exp);
+ TEST_FN_FUNC_FN(exp2);
+ TEST_FN_FUNC_FN(exp10);
+ TEST_FN_FUNC_FN(expm1);
+ TEST_FN_FUNC_FN(fabs);
+ TEST_FN_FUNC_FN_FN(fdim);
+ TEST_FN_FUNC_FN(floor);
+ TEST_FN_FUNC_FN_FN_FN(fma);
+ TEST_FN_FUNC_FN_FN(fmax);
+ TEST_FN_FUNC_FN_F(fmax);
+ TEST_FN_FUNC_FN_FN(fmin);
+ TEST_FN_FUNC_FN_F(fmin);
+ TEST_FN_FUNC_FN_FN(fmod);
+ TEST_FN_FUNC_FN_PFN(fract);
+ TEST_FN_FUNC_FN_PIN(frexp);
+ TEST_FN_FUNC_FN_FN(hypot);
+ TEST_IN_FUNC_FN(ilogb);
+ TEST_FN_FUNC_FN_IN(ldexp);
+ TEST_FN_FUNC_FN_I(ldexp);
+ TEST_F_FUNC_FN(length);
+ TEST_FN_FUNC_FN(lgamma);
+ TEST_FN_FUNC_FN_PIN(lgamma);
+ TEST_FN_FUNC_FN(log);
+ TEST_FN_FUNC_FN(log2);
+ TEST_FN_FUNC_FN(log10);
+ TEST_FN_FUNC_FN(log1p);
+ TEST_FN_FUNC_FN(logb);
+ TEST_FN_FUNC_FN_FN_FN(mad);
+ TEST_FN_FUNC_FN_FN(max);
+ TEST_FN_FUNC_FN_F(max);
+ TEST_FN_FUNC_FN_FN(min);
+ TEST_FN_FUNC_FN_F(min);
+ TEST_FN_FUNC_FN_FN_FN(mix);
+ TEST_FN_FUNC_FN_FN_F(mix);
+ TEST_FN_FUNC_FN_PFN(modf);
+ // nan
+ TEST_FN_FUNC_FN_FN(nextafter);
+ TEST_FN_FUNC_FN(normalize);
+ TEST_FN_FUNC_FN_FN(pow);
+ TEST_FN_FUNC_FN_IN(pown);
+ TEST_FN_FUNC_FN_FN(powr);
+ TEST_FN_FUNC_FN(radians);
+ TEST_FN_FUNC_FN_FN(remainder);
+ TEST_FN_FUNC_FN_FN_PIN(remquo);
+ TEST_FN_FUNC_FN(rint);
+ TEST_FN_FUNC_FN_IN(rootn);
+ TEST_FN_FUNC_FN(round);
+ TEST_FN_FUNC_FN(rsqrt);
+ TEST_FN_FUNC_FN(sign);
+ TEST_FN_FUNC_FN(sin);
+ TEST_FN_FUNC_FN_PFN(sincos);
+ TEST_FN_FUNC_FN(sinh);
+ TEST_FN_FUNC_FN(sinpi);
+ TEST_FN_FUNC_FN(sqrt);
+ TEST_FN_FUNC_FN_FN(step);
+ TEST_FN_FUNC_FN_F(step);
+ TEST_FN_FUNC_FN(tan);
+ TEST_FN_FUNC_FN(tanh);
+ TEST_FN_FUNC_FN(tanpi);
+ TEST_FN_FUNC_FN(tgamma);
+ TEST_FN_FUNC_FN(trunc);
+
+ float time = end(index);
+
+ if (failed) {
+ rsDebug("test_fp_math FAILED", time);
+ }
+ else {
+ rsDebug("test_fp_math PASSED", time);
+ }
+
+ return failed;
+}
+
+static bool test_int_math(uint32_t index) {
+ bool failed = false;
+ start();
+
+ TEST_UIN_FUNC_IN(abs);
+ TEST_IN_FUNC_IN(clz);
+ TEST_IN_FUNC_IN_IN(min);
+ TEST_IN_FUNC_IN_IN(max);
+ TEST_I_FUNC_I_I_I(rsClamp);
+
+ float time = end(index);
+
+ if (failed) {
+ rsDebug("test_int_math FAILED", time);
+ }
+ else {
+ rsDebug("test_int_math PASSED", time);
+ }
+
+ return failed;
+}
static bool test_basic_operators() {
bool failed = false;
@@ -310,6 +423,7 @@
bool failed = false;
failed |= test_convert();
failed |= test_fp_math(index);
+ failed |= test_int_math(index);
failed |= test_basic_operators();
if (failed) {
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index c553947..f417ddd 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -442,6 +442,7 @@
if (wasConnected) {
mLocalIp = null;
+ stopPortMappingMeasurement();
for (SipSessionGroupExt group : mSipGroups.values()) {
group.onConnectivityChanged(false);
}
@@ -457,7 +458,6 @@
if (isWifi && (mWifiLock != null)) stopWifiScanner();
} else {
mMyWakeLock.reset(); // in case there's a leak
- stopPortMappingMeasurement();
if (isWifi && (mWifiLock != null)) startWifiScanner();
}
} catch (SipException e) {
@@ -784,52 +784,50 @@
private static final int PASS_THRESHOLD = 10;
private static final int MAX_RETRY_COUNT = 5;
private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
+ private SipProfile mLocalProfile;
private SipSessionGroupExt mGroup;
private SipSessionGroup.SipSessionImpl mSession;
private int mMinInterval;
private int mMaxInterval;
private int mInterval;
- private int mPassCount = 0;
+ private int mPassCount;
public IntervalMeasurementProcess(SipProfile localProfile,
int minInterval, int maxInterval) {
mMaxInterval = maxInterval;
mMinInterval = minInterval;
- mInterval = (maxInterval + minInterval) / 2;
-
- // Don't start measurement if the interval is too small
- if (mInterval < DEFAULT_KEEPALIVE_INTERVAL) {
- Log.w(TAG, "interval is too small; measurement aborted; "
- + "maxInterval=" + mMaxInterval);
- return;
- } else if (checkTermination()) {
- Log.w(TAG, "interval is too small; measurement aborted; "
- + "interval=[" + mMinInterval + "," + mMaxInterval
- + "]");
- return;
- }
-
- try {
- mGroup = new SipSessionGroupExt(localProfile, null, null);
- // TODO: remove this line once SipWakeupTimer can better handle
- // variety of timeout values
- mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
- } catch (Exception e) {
- Log.w(TAG, "start interval measurement error: " + e);
- }
+ mLocalProfile = localProfile;
}
public void start() {
synchronized (SipService.this) {
- Log.d(TAG, "start measurement w interval=" + mInterval);
- if (mSession == null) {
+ if (mSession != null) {
+ return;
+ }
+
+ mInterval = (mMaxInterval + mMinInterval) / 2;
+ mPassCount = 0;
+
+ // Don't start measurement if the interval is too small
+ if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) {
+ Log.w(TAG, "measurement aborted; interval=[" +
+ mMinInterval + "," + mMaxInterval + "]");
+ return;
+ }
+
+ try {
+ Log.d(TAG, "start measurement w interval=" + mInterval);
+
+ mGroup = new SipSessionGroupExt(mLocalProfile, null, null);
+ // TODO: remove this line once SipWakeupTimer can better handle
+ // variety of timeout values
+ mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
+
mSession = (SipSessionGroup.SipSessionImpl)
mGroup.createSession(null);
- }
- try {
mSession.startKeepAliveProcess(mInterval, this);
- } catch (SipException e) {
- Log.e(TAG, "start()", e);
+ } catch (Throwable t) {
+ onError(SipErrorCode.CLIENT_ERROR, t.toString());
}
}
}
@@ -840,6 +838,10 @@
mSession.stopKeepAliveProcess();
mSession = null;
}
+ if (mGroup != null) {
+ mGroup.close();
+ mGroup = null;
+ }
mTimer.cancel(this);
}
}
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index eb5cce7..06cdaf2 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -100,7 +100,7 @@
private static final int EXPIRY_TIME = 3600; // in seconds
private static final int CANCEL_CALL_TIMER = 3; // in seconds
private static final int END_CALL_TIMER = 3; // in seconds
- private static final int KEEPALIVE_TIMEOUT = 3; // in seconds
+ private static final int KEEPALIVE_TIMEOUT = 5; // in seconds
private static final int INCALL_KEEPALIVE_INTERVAL = 10; // in seconds
private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds
@@ -1555,7 +1555,7 @@
try {
sendKeepAlive();
} catch (Throwable t) {
- Log.w(TAG, "keepalive error: " + ": "
+ Log.w(TAG, "keepalive error: "
+ mLocalProfile.getUriString(), getRootCause(t));
// It's possible that the keepalive process is being stopped
// during session.sendKeepAlive() so need to check mRunning
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 93c809e..459756d 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -28,6 +28,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
+// #define LOG_NDEBUG 0
#define LOG_TAG "AudioGroup"
#include <cutils/atomic.h>
#include <cutils/properties.h>
@@ -62,9 +63,9 @@
// a modulo operation on the index while accessing the array. However modulo can
// be expensive on some platforms, such as ARM. Thus we round up the size of the
// array to the nearest power of 2 and then use bitwise-and instead of modulo.
-// Currently we make it 512ms long and assume packet interval is 40ms or less.
-// The first 80ms is the place where samples get mixed. The rest 432ms is the
-// real jitter buffer. For a stream at 8000Hz it takes 8192 bytes. These numbers
+// Currently we make it 2048ms long and assume packet interval is 50ms or less.
+// The first 100ms is the place where samples get mixed. The rest is the real
+// jitter buffer. For a stream at 8000Hz it takes 32 kilobytes. These numbers
// are chosen by experiments and each of them can be adjusted as needed.
// Originally a stream does not send packets when it is receive-only or there is
@@ -84,9 +85,11 @@
// + Resampling is not done yet, so streams in one group must use the same rate.
// For the first release only 8000Hz is supported.
-#define BUFFER_SIZE 512
-#define HISTORY_SIZE 80
-#define MEASURE_PERIOD 2000
+#define BUFFER_SIZE 2048
+#define HISTORY_SIZE 100
+#define MEASURE_BASE 100
+#define MEASURE_PERIOD 5000
+#define DTMF_PERIOD 200
class AudioStream
{
@@ -278,7 +281,7 @@
if (mMode != RECEIVE_ONLY && mDtmfEvent != -1) {
int duration = mTimestamp - mDtmfStart;
// Make sure duration is reasonable.
- if (duration >= 0 && duration < mSampleRate * 100) {
+ if (duration >= 0 && duration < mSampleRate * DTMF_PERIOD) {
duration += mSampleCount;
int32_t buffer[4] = {
htonl(mDtmfMagic | mSequence),
@@ -286,7 +289,7 @@
mSsrc,
htonl(mDtmfEvent | duration),
};
- if (duration >= mSampleRate * 100) {
+ if (duration >= mSampleRate * DTMF_PERIOD) {
buffer[3] |= htonl(1 << 23);
mDtmfEvent = -1;
}
@@ -298,43 +301,39 @@
}
int32_t buffer[mSampleCount + 3];
+ bool data = false;
+ if (mMode != RECEIVE_ONLY) {
+ // Mix all other streams.
+ memset(buffer, 0, sizeof(buffer));
+ while (chain) {
+ if (chain != this) {
+ data |= chain->mix(buffer, tick - mInterval, tick, mSampleRate);
+ }
+ chain = chain->mNext;
+ }
+ }
+
int16_t samples[mSampleCount];
- if (mMode == RECEIVE_ONLY) {
+ if (data) {
+ // Saturate into 16 bits.
+ for (int i = 0; i < mSampleCount; ++i) {
+ int32_t sample = buffer[i];
+ if (sample < -32768) {
+ sample = -32768;
+ }
+ if (sample > 32767) {
+ sample = 32767;
+ }
+ samples[i] = sample;
+ }
+ } else {
if ((mTick ^ mKeepAlive) >> 10 == 0) {
return;
}
mKeepAlive = mTick;
memset(samples, 0, sizeof(samples));
- } else {
- // Mix all other streams.
- bool mixed = false;
- memset(buffer, 0, sizeof(buffer));
- while (chain) {
- if (chain != this &&
- chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
- mixed = true;
- }
- chain = chain->mNext;
- }
- if (mixed) {
- // Saturate into 16 bits.
- for (int i = 0; i < mSampleCount; ++i) {
- int32_t sample = buffer[i];
- if (sample < -32768) {
- sample = -32768;
- }
- if (sample > 32767) {
- sample = 32767;
- }
- samples[i] = sample;
- }
- } else {
- if ((mTick ^ mKeepAlive) >> 10 == 0) {
- return;
- }
- mKeepAlive = mTick;
- memset(samples, 0, sizeof(samples));
+ if (mMode != RECEIVE_ONLY) {
LOGV("stream[%d] no data", mSocket);
}
}
@@ -380,19 +379,16 @@
}
}
- // Adjust the jitter buffer if the latency keeps larger than two times of the
- // packet interval in the past two seconds.
- int score = mBufferTail - tick - mInterval * 2;
- if (mLatencyScore > score) {
+ // Adjust the jitter buffer if the latency keeps larger than the threshold
+ // in the measurement period.
+ int score = mBufferTail - tick - MEASURE_BASE;
+ if (mLatencyScore > score || mLatencyScore <= 0) {
mLatencyScore = score;
- }
- if (mLatencyScore <= 0) {
mLatencyTimer = tick;
- mLatencyScore = score;
} else if (tick - mLatencyTimer >= MEASURE_PERIOD) {
LOGV("stream[%d] reduces latency of %dms", mSocket, mLatencyScore);
mBufferTail -= mLatencyScore;
- mLatencyTimer = tick;
+ mLatencyScore = -1;
}
int count = (BUFFER_SIZE - (mBufferTail - mBufferHead)) * mSampleRate;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 27a60cd..61dfebf 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -18,8 +18,6 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.Wps;
-import android.net.wifi.WpsResult;
import android.net.wifi.ScanResult;
import android.net.DhcpInfo;
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index c75dec7..18d6eaa 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -397,7 +397,7 @@
* Start WPS pin method configuration with pin obtained
* from the access point
*/
- static WpsResult startWpsWithPinFromAccessPoint(Wps config) {
+ static WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) {
WpsResult result = new WpsResult();
if (WifiNative.startWpsWithPinFromAccessPointCommand(config.BSSID, config.pin)) {
/* WPS leaves all networks disabled */
@@ -415,7 +415,7 @@
* from the device
* @return WpsResult indicating status and pin
*/
- static WpsResult startWpsWithPinFromDevice(Wps config) {
+ static WpsResult startWpsWithPinFromDevice(WpsInfo config) {
WpsResult result = new WpsResult();
result.pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID);
/* WPS leaves all networks disabled */
@@ -432,7 +432,7 @@
/**
* Start WPS push button configuration
*/
- static WpsResult startWpsPbc(Wps config) {
+ static WpsResult startWpsPbc(WpsInfo config) {
WpsResult result = new WpsResult();
if (WifiNative.startWpsPbcCommand(config.BSSID)) {
/* WPS leaves all networks disabled */
@@ -594,7 +594,7 @@
sendConfiguredNetworksChangedBroadcast();
}
- static void updateIpAndProxyFromWpsConfig(int netId, Wps wpsConfig) {
+ static void updateIpAndProxyFromWpsConfig(int netId, WpsInfo wpsConfig) {
synchronized (sConfiguredNetworks) {
WifiConfiguration config = sConfiguredNetworks.get(netId);
if (config != null) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0fce8e8..40ac2a0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1175,7 +1175,7 @@
* @param config WPS configuration
* @hide
*/
- public void startWps(Wps config) {
+ public void startWps(WpsInfo config) {
if (config == null) {
return;
}
@@ -1630,4 +1630,4 @@
return false;
}
}
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 6cc09e9..a6ea6d4 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -261,23 +261,23 @@
public static String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
if (config == null) return null;
List<String> args = new ArrayList<String>();
- Wps wps = config.wps;
+ WpsInfo wps = config.wps;
args.add(config.deviceAddress);
switch (wps.setup) {
- case PBC:
+ case WpsInfo.PBC:
args.add("pbc");
break;
- case DISPLAY:
+ case WpsInfo.DISPLAY:
//TODO: pass the pin back for display
args.add("pin");
args.add("display");
break;
- case KEYPAD:
+ case WpsInfo.KEYPAD:
args.add(wps.pin);
args.add("keypad");
break;
- case LABEL:
+ case WpsInfo.LABEL:
args.add(wps.pin);
args.add("label");
default:
@@ -303,6 +303,10 @@
return doStringCommand(command);
}
+ public static boolean p2pCancelConnect() {
+ return doBooleanCommand("P2P_CANCEL");
+ }
+
public static boolean p2pGroupAdd() {
return doBooleanCommand("P2P_GROUP_ADD");
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 175a9ce..3b29d40 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -880,7 +880,7 @@
sendMessage(message);
}
- public void startWps(Messenger replyTo, Wps config) {
+ public void startWps(Messenger replyTo, WpsInfo config) {
Message msg = obtainMessage(CMD_START_WPS, config);
msg.replyTo = replyTo;
sendMessage(msg);
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 956c3f2..c34c4645 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -162,7 +162,7 @@
* Fetch NetworkInfo for the network
*/
public NetworkInfo getNetworkInfo() {
- return mNetworkInfo;
+ return new NetworkInfo(mNetworkInfo);
}
/**
@@ -242,7 +242,8 @@
} else {
mLastState = state;
}
- Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
+ new NetworkInfo(mNetworkInfo));
msg.sendToTarget();
} else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
mLinkProperties = (LinkProperties) intent.getParcelableExtra(
diff --git a/wifi/java/android/net/wifi/Wps.aidl b/wifi/java/android/net/wifi/WpsInfo.aidl
similarity index 88%
rename from wifi/java/android/net/wifi/Wps.aidl
rename to wifi/java/android/net/wifi/WpsInfo.aidl
index ba82a9a..f5e4ebe 100644
--- a/wifi/java/android/net/wifi/Wps.aidl
+++ b/wifi/java/android/net/wifi/WpsInfo.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2010, The Android Open Source Project
+ * Copyright (c) 2011, 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.
@@ -16,4 +16,4 @@
package android.net.wifi;
-parcelable Wps;
+parcelable WpsInfo;
diff --git a/wifi/java/android/net/wifi/Wps.java b/wifi/java/android/net/wifi/WpsInfo.java
similarity index 70%
rename from wifi/java/android/net/wifi/Wps.java
rename to wifi/java/android/net/wifi/WpsInfo.java
index 6d006960..f70e5af 100644
--- a/wifi/java/android/net/wifi/Wps.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -26,27 +26,24 @@
/**
* A class representing Wi-Fi Protected Setup
- * @hide
*
* {@see WifiP2pConfig}
*/
-public class Wps implements Parcelable {
+public class WpsInfo implements Parcelable {
+
+ /** Push button configuration */
+ public static final int PBC = 0;
+ /** Display pin method configuration - pin is generated and displayed on device */
+ public static final int DISPLAY = 1;
+ /** Keypad pin method configuration - pin is entered on device */
+ public static final int KEYPAD = 2;
+ /** Label pin method configuration - pin is labelled on device */
+ public static final int LABEL = 3;
+ /** Invalid configuration */
+ public static final int INVALID = 4;
/** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
- public enum Setup {
- /* Push button configuration */
- PBC,
- /* Display pin method configuration - pin is generated and displayed on device */
- DISPLAY,
- /* Keypad pin method configuration - pin is entered on device */
- KEYPAD,
- /* Label pin method configuration - pin is obtained from a printed label */
- LABEL,
- /* Invalid config */
- INVALID
- }
-
- public Setup setup;
+ public int setup;
/** @hide */
public String BSSID;
@@ -63,8 +60,8 @@
/** @hide */
public LinkProperties linkProperties;
- public Wps() {
- setup = Setup.INVALID;
+ public WpsInfo() {
+ setup = INVALID;
BSSID = null;
pin = null;
ipAssignment = IpAssignment.UNASSIGNED;
@@ -72,10 +69,9 @@
linkProperties = new LinkProperties();
}
- /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
- sbuf.append(" setup: ").append(setup.toString());
+ sbuf.append(" setup: ").append(setup);
sbuf.append('\n');
sbuf.append(" BSSID: ").append(BSSID);
sbuf.append('\n');
@@ -90,13 +86,13 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** copy constructor {@hide} */
- public Wps(Wps source) {
+ /* Copy constructor */
+ public WpsInfo(WpsInfo source) {
if (source != null) {
setup = source.setup;
BSSID = source.BSSID;
@@ -107,9 +103,9 @@
}
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(setup.name());
+ dest.writeInt(setup);
dest.writeString(BSSID);
dest.writeString(pin);
dest.writeString(ipAssignment.name());
@@ -117,12 +113,12 @@
dest.writeParcelable(linkProperties, flags);
}
- /** Implement the Parcelable interface {@hide} */
- public static final Creator<Wps> CREATOR =
- new Creator<Wps>() {
- public Wps createFromParcel(Parcel in) {
- Wps config = new Wps();
- config.setup = Setup.valueOf(in.readString());
+ /** Implement the Parcelable interface */
+ public static final Creator<WpsInfo> CREATOR =
+ new Creator<WpsInfo>() {
+ public WpsInfo createFromParcel(Parcel in) {
+ WpsInfo config = new WpsInfo();
+ config.setup = in.readInt();
config.BSSID = in.readString();
config.pin = in.readString();
config.ipAssignment = IpAssignment.valueOf(in.readString());
@@ -131,8 +127,8 @@
return config;
}
- public Wps[] newArray(int size) {
- return new Wps[size];
+ public WpsInfo[] newArray(int size) {
+ return new WpsInfo[size];
}
};
}
diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java
index f9e903a..c14a8db 100644
--- a/wifi/java/android/net/wifi/WpsStateMachine.java
+++ b/wifi/java/android/net/wifi/WpsStateMachine.java
@@ -53,7 +53,7 @@
private WifiStateMachine mWifiStateMachine;
- private Wps mWpsConfig;
+ private WpsInfo mWpsInfo;
private Context mContext;
AsyncChannel mReplyChannel = new AsyncChannel();
@@ -90,20 +90,20 @@
@Override
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- Wps wpsConfig;
+ WpsInfo wpsConfig;
switch (message.what) {
case WifiStateMachine.CMD_START_WPS:
- mWpsConfig = (Wps) message.obj;
+ mWpsInfo = (WpsInfo) message.obj;
WpsResult result;
- switch (mWpsConfig.setup) {
- case PBC:
- result = WifiConfigStore.startWpsPbc(mWpsConfig);
+ switch (mWpsInfo.setup) {
+ case WpsInfo.PBC:
+ result = WifiConfigStore.startWpsPbc(mWpsInfo);
break;
- case KEYPAD:
- result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsConfig);
+ case WpsInfo.KEYPAD:
+ result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsInfo);
break;
- case DISPLAY:
- result = WifiConfigStore.startWpsWithPinFromDevice(mWpsConfig);
+ case WpsInfo.DISPLAY:
+ result = WifiConfigStore.startWpsWithPinFromDevice(mWpsInfo);
break;
default:
result = new WpsResult(Status.FAILURE);
@@ -114,7 +114,7 @@
if (result.status == Status.SUCCESS) {
transitionTo(mActiveState);
} else {
- Log.e(TAG, "Failed to start WPS with config " + mWpsConfig.toString());
+ Log.e(TAG, "Failed to start WPS with config " + mWpsInfo.toString());
}
break;
case WifiStateMachine.CMD_RESET_WPS_STATE:
@@ -154,7 +154,7 @@
WifiConfigStore.enableAllNetworks();
WifiConfigStore.loadConfiguredNetworks();
WifiConfigStore.updateIpAndProxyFromWpsConfig(
- stateChangeResult.networkId, mWpsConfig);
+ stateChangeResult.networkId, mWpsInfo);
mWifiStateMachine.sendMessage(WifiStateMachine.WPS_COMPLETED_EVENT);
transitionTo(mInactiveState);
break;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index e359ce5..e0c1b13 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -16,14 +16,12 @@
package android.net.wifi.p2p;
-import android.net.wifi.Wps;
-import android.net.wifi.Wps.Setup;
+import android.net.wifi.WpsInfo;
import android.os.Parcelable;
import android.os.Parcel;
/**
* A class representing a Wi-Fi P2p configuration for setting up a connection
- * @hide
*
* {@see WifiP2pManager}
*/
@@ -37,7 +35,7 @@
/**
* Wi-Fi Protected Setup information
*/
- public Wps wps;
+ public WpsInfo wps;
/**
* This is an integer value between 0 and 15 where 0 indicates the least
@@ -63,8 +61,8 @@
public WifiP2pConfig() {
//set defaults
- wps = new Wps();
- wps.setup = Setup.PBC;
+ wps = new WpsInfo();
+ wps.setup = WpsInfo.PBC;
}
/** P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 {@hide}*/
@@ -76,7 +74,7 @@
}
deviceAddress = tokens[1];
- wps = new Wps();
+ wps = new WpsInfo();
if (tokens.length > 2) {
String[] nameVal = tokens[2].split("=");
@@ -89,25 +87,24 @@
//As defined in wps/wps_defs.h
switch (devPasswdId) {
case 0x00:
- wps.setup = Setup.LABEL;
+ wps.setup = WpsInfo.LABEL;
break;
case 0x01:
- wps.setup = Setup.KEYPAD;
+ wps.setup = WpsInfo.KEYPAD;
break;
case 0x04:
- wps.setup = Setup.PBC;
+ wps.setup = WpsInfo.PBC;
break;
case 0x05:
- wps.setup = Setup.DISPLAY;
+ wps.setup = WpsInfo.DISPLAY;
break;
default:
- wps.setup = Setup.PBC;
+ wps.setup = WpsInfo.PBC;
break;
}
}
}
- /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("\n address: ").append(deviceAddress);
@@ -117,19 +114,22 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** copy constructor {@hide} */
+ /** copy constructor */
public WifiP2pConfig(WifiP2pConfig source) {
if (source != null) {
- //TODO: implement
- }
+ deviceAddress = source.deviceAddress;
+ wps = new WpsInfo(source.wps);
+ groupOwnerIntent = source.groupOwnerIntent;
+ persist = source.persist;
+ }
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(deviceAddress);
dest.writeParcelable(wps, flags);
@@ -137,13 +137,13 @@
dest.writeString(persist.name());
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public static final Creator<WifiP2pConfig> CREATOR =
new Creator<WifiP2pConfig>() {
public WifiP2pConfig createFromParcel(Parcel in) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = in.readString();
- config.wps = (Wps) in.readParcelable(null);
+ config.wps = (WpsInfo) in.readParcelable(null);
config.groupOwnerIntent = in.readInt();
config.persist = Persist.valueOf(in.readString());
return config;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 99c585f..1b0c301 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -24,7 +24,6 @@
/**
* A class representing a Wi-Fi p2p device
- * @hide
*
* {@see WifiP2pManager}
*/
@@ -109,18 +108,16 @@
*/
public int groupCapability;
+ public static final int CONNECTED = 0;
+ public static final int INVITED = 1;
+ public static final int FAILED = 2;
+ public static final int AVAILABLE = 3;
+ public static final int UNAVAILABLE = 4;
+
/** Device connection status */
- public enum Status {
- CONNECTED,
- INVITED,
- FAILED,
- AVAILABLE,
- UNAVAILABLE,
- }
+ public int status = UNAVAILABLE;
- public Status status = Status.UNAVAILABLE;
-
- WifiP2pDevice() {
+ public WifiP2pDevice() {
}
/**
@@ -197,7 +194,7 @@
}
if (tokens[0].startsWith("P2P-DEVICE-FOUND")) {
- status = Status.AVAILABLE;
+ status = AVAILABLE;
}
}
@@ -227,7 +224,6 @@
}
@Override
- /** @hide */
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof WifiP2pDevice)) return false;
@@ -239,7 +235,6 @@
return other.deviceAddress.equals(deviceAddress);
}
- /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("Device: ").append(deviceName);
@@ -254,12 +249,12 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** copy constructor {@hide} */
+ /** copy constructor */
public WifiP2pDevice(WifiP2pDevice source) {
if (source != null) {
deviceName = source.deviceName;
@@ -274,7 +269,7 @@
}
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(deviceName);
dest.writeString(deviceAddress);
@@ -284,10 +279,10 @@
dest.writeInt(wpsConfigMethodsSupported);
dest.writeInt(deviceCapability);
dest.writeInt(groupCapability);
- dest.writeString(status.name());
+ dest.writeInt(status);
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public static final Creator<WifiP2pDevice> CREATOR =
new Creator<WifiP2pDevice>() {
public WifiP2pDevice createFromParcel(Parcel in) {
@@ -300,7 +295,7 @@
device.wpsConfigMethodsSupported = in.readInt();
device.deviceCapability = in.readInt();
device.groupCapability = in.readInt();
- device.status = Status.valueOf(in.readString());
+ device.status = in.readInt();
return device;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index 242bce0..9ce2545 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -27,7 +27,6 @@
/**
* A class representing a Wi-Fi P2p device list
- * @hide
*
* {@see WifiP2pManager}
*/
@@ -35,11 +34,11 @@
private Collection<WifiP2pDevice> mDevices;
- WifiP2pDeviceList() {
+ public WifiP2pDeviceList() {
mDevices = new ArrayList<WifiP2pDevice>();
}
- /** copy constructor {@hide} */
+ /** copy constructor */
public WifiP2pDeviceList(WifiP2pDeviceList source) {
if (source != null) {
mDevices = source.getDeviceList();
@@ -91,7 +90,6 @@
return Collections.unmodifiableCollection(mDevices);
}
- /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
for (WifiP2pDevice device : mDevices) {
@@ -100,12 +98,12 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mDevices.size());
for(WifiP2pDevice device : mDevices) {
@@ -113,7 +111,7 @@
}
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public static final Creator<WifiP2pDeviceList> CREATOR =
new Creator<WifiP2pDeviceList>() {
public WifiP2pDeviceList createFromParcel(Parcel in) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 48f210b..9473993 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -26,7 +26,6 @@
/**
* A class representing a Wi-Fi P2p group
- * @hide
*
* {@see WifiP2pManager}
*/
@@ -49,7 +48,7 @@
private String mInterface;
- WifiP2pGroup() {
+ public WifiP2pGroup() {
}
/**
@@ -202,7 +201,6 @@
return mInterface;
}
- /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("network: ").append(mNetworkName);
@@ -215,19 +213,24 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** copy constructor {@hide} */
- // TODO: implement
+ /** copy constructor */
public WifiP2pGroup(WifiP2pGroup source) {
if (source != null) {
- }
+ mNetworkName = source.getNetworkName();
+ mOwner = new WifiP2pDevice(source.getOwner());
+ mIsGroupOwner = source.mIsGroupOwner;
+ for (WifiP2pDevice d : source.getClientList()) mClients.add(d);
+ mPassphrase = source.getPassphrase();
+ mInterface = source.getInterface();
+ }
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mNetworkName);
dest.writeParcelable(mOwner, flags);
@@ -240,7 +243,7 @@
dest.writeString(mInterface);
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public static final Creator<WifiP2pGroup> CREATOR =
new Creator<WifiP2pGroup>() {
public WifiP2pGroup createFromParcel(Parcel in) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index 81b7708..dce315a 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -24,7 +24,6 @@
/**
* A class representing connection information about a Wi-Fi p2p group
- * @hide
*
* {@see WifiP2pManager}
*/
@@ -39,11 +38,9 @@
/** Group owner address */
public InetAddress groupOwnerAddress;
- /** @hide */
- WifiP2pInfo() {
+ public WifiP2pInfo() {
}
- /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("groupFormed: ").append(groupFormed)
@@ -52,12 +49,12 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** copy constructor {@hide} */
+ /** copy constructor */
public WifiP2pInfo(WifiP2pInfo source) {
if (source != null) {
groupFormed = source.groupFormed;
@@ -66,7 +63,7 @@
}
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte(groupFormed ? (byte)1 : (byte)0);
dest.writeByte(isGroupOwner ? (byte)1 : (byte)0);
@@ -79,7 +76,7 @@
}
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public static final Creator<WifiP2pInfo> CREATOR =
new Creator<WifiP2pInfo>() {
public WifiP2pInfo createFromParcel(Parcel in) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 5715186..9205300 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -24,6 +24,7 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -34,36 +35,44 @@
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
+import java.util.HashMap;
+
/**
* This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
* application discover available peers, setup connection to peers and query for the list of peers.
* When a p2p connection is formed over wifi, the device continues to maintain the uplink
* connection over mobile or any other available network for internet connectivity on the device.
*
- * <p> The API is asynchronous and response to a request from an application is sent in the form
- * of a {@link android.os.Message} on a {@link android.os.Handler} that needs to be initialized
- * by the application right at the beginning before any p2p operations are performed via
- * {@link #initialize}.
+ * <p> The API is asynchronous and responses to requests from an application are on listener
+ * callbacks provided by the application. The application needs to do an initialization with
+ * {@link #initialize} before doing any p2p operation.
*
- * <p> An application can request for the current list of peers using {@link #requestPeers}. The
- * {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is available.
- * Use {@link #peersInResponse} to extract the peer device list upon the receiving the
- * {@link #RESPONSE_PEERS} message.
+ * <p> Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect},
+ * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for
+ * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
+ * Action callbacks indicate whether the initiation of the action was a success or a failure.
+ * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
+ * or {@link #BUSY}.
*
- * <p> If an application needs to initiate a discovery, use {@link #discoverPeers} and listen
- * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to initiate a request to fetch
- * list of peers with {@link #requestPeers}. An initiated discovery request from an application
- * stays active until the device starts connecting to a peer or forms a p2p group.
+ * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
+ * discovery request from an application stays active until the device starts connecting to a peer
+ * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the
+ * discovery initiation was successful or failure. Additionally, applications can listen
+ * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes.
+ *
+ * <p> When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received
+ * or when an application needs to fetch the current list of peers, it can request the list
+ * of peers with {@link #requestPeers}. When the peer list is available
+ * {@link PeerListListener#onPeersAvailable} is called with the device list.
*
* <p> An application can initiate a connection request to a peer through {@link #connect}. See
* {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
* Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
* which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
- *
+*
* <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
- * use {@link #requestConnectionInfo} to fetch the connection details. Connection information
- * can be obtained with {@link #connectionInfoInResponse} on a {@link #RESPONSE_CONNECTION_INFO}
- * message. The connection info {@link WifiP2pInfo} contains the address of the group owner
+ * use {@link #requestConnectionInfo} to fetch the connection details. The connection info
+ * {@link WifiP2pInfo} contains the address of the group owner
* {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
* if the current device is a p2p group owner. A p2p client can thus communicate with
* the p2p group owner through a socket connection.
@@ -85,10 +94,10 @@
* {@see WifiP2pGroup}
* {@see WifiP2pDevice}
* {@see WifiP2pDeviceList}
- * {@see android.net.wifi.Wps}
- * @hide
+ * {@see android.net.wifi.WpsInfo}
*/
public class WifiP2pManager {
+ private static final String TAG = "WifiP2pManager";
/**
* Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
* extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
@@ -97,7 +106,7 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_P2P_STATE_CHANGED_ACTION =
- "android.net.wifi.P2P_STATE_CHANGED";
+ "android.net.wifi.p2p.STATE_CHANGED";
/**
* The lookup key for an int that indicates whether Wi-Fi p2p is enabled or disabled.
@@ -133,7 +142,7 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION =
- "android.net.wifi.CONNECTION_STATE_CHANGE";
+ "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
/**
* The lookup key for a {@link android.net.wifi.p2p.WifiP2pInfo} object
@@ -170,27 +179,23 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
- "android.net.wifi.PEERS_CHANGED";
+ "android.net.wifi.p2p.PEERS_CHANGED";
/**
- * Activity Action: Pick a Wi-Fi p2p network to connect to.
- * <p>Input: Nothing.
- * <p>Output: Nothing.
- * @hide
+ * Broadcast intent action indicating that this device details have changed.
*/
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_PICK_WIFI_P2P_NETWORK =
- "android.net.wifi.PICK_WIFI_P2P_NETWORK";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION =
+ "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
+
+ /**
+ * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
+ * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
+ */
+ public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
IWifiP2pManager mService;
- /**
- * Message {@link android.os.Message#what} sent on the application handler specified
- * at {@link #initialize} indicating the asynchronous channel has disconnected. An
- * application could choose to reconnect with {@link #initialize}
- */
- public static final int HANDLER_DISCONNECTION = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
-
private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
/** @hide */
@@ -209,150 +214,59 @@
/** @hide */
public static final int DISCOVER_PEERS = BASE + 7;
-
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
- * operation failed.
- * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
- * or {@link #BUSY}
- */
+ /** @hide */
public static final int DISCOVER_PEERS_FAILED = BASE + 8;
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
- * operation succeeded.
- * <p> The application can register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent
- * to listen for changes in the peer list as a result of the discovery process.
- */
+ /** @hide */
public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 9;
/** @hide */
public static final int CONNECT = BASE + 10;
-
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #connect}
- * operation failed.
- * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
- * or {@link #BUSY}
- */
+ /** @hide */
public static final int CONNECT_FAILED = BASE + 11;
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #connect}
- * operation succeeded.
- * <p> The application can register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent
- * to listen for connectivity change as a result of the connect operation
- */
+ /** @hide */
public static final int CONNECT_SUCCEEDED = BASE + 12;
/** @hide */
- public static final int CREATE_GROUP = BASE + 13;
-
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
- * operation failed.
- * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
- * or {@link #BUSY}
- */
- public static final int CREATE_GROUP_FAILED = BASE + 14;
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
- * operation succeeded.
- * <p> The application can request the group details with {@link #requestGroupInfo}
- */
- public static final int CREATE_GROUP_SUCCEEDED = BASE + 15;
+ public static final int CANCEL_CONNECT = BASE + 13;
+ /** @hide */
+ public static final int CANCEL_CONNECT_FAILED = BASE + 14;
+ /** @hide */
+ public static final int CANCEL_CONNECT_SUCCEEDED = BASE + 15;
/** @hide */
- public static final int REMOVE_GROUP = BASE + 16;
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
- * operation failed.
- * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
- * or {@link #BUSY}
- */
- public static final int REMOVE_GROUP_FAILED = BASE + 17;
- /**
- * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
- * operation succeeded.
- */
- public static final int REMOVE_GROUP_SUCCEEDED = BASE + 18;
-
- /**
- * Supported {@link android.os.Message#arg1} value on the following response messages:
- * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
- * and {@link #REMOVE_GROUP_FAILED}
- *
- * <p> This indicates that the operation failed due to an internal error
- */
- public static final int ERROR = 0;
-
- /**
- * Supported {@link android.os.Message#arg1} value on the following response messages:
- * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
- * and {@link #REMOVE_GROUP_FAILED}
- *
- * <p> This indicates that the operation failed because p2p is unsupported on the
- * device
- */
- public static final int P2P_UNSUPPORTED = 1;
-
- /**
- * Supported {@link android.os.Message#arg1} value on the following response messages:
- * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
- * and {@link #REMOVE_GROUP_FAILED}
- *
- * <p> This indicates that the operation failed because the framework is busy and
- * unable to service the request
- */
- public static final int BUSY = 2;
+ public static final int CREATE_GROUP = BASE + 16;
+ /** @hide */
+ public static final int CREATE_GROUP_FAILED = BASE + 17;
+ /** @hide */
+ public static final int CREATE_GROUP_SUCCEEDED = BASE + 18;
/** @hide */
- public static final int REQUEST_PEERS = BASE + 19;
- /**
- * Message {@link android.os.Message#what} delivered on the application hander
- * in response to a {@link #requestPeers} call from the application.
- *
- * <p> Extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
- * on the message object
- */
- public static final int RESPONSE_PEERS = BASE + 20;
+ public static final int REMOVE_GROUP = BASE + 19;
+ /** @hide */
+ public static final int REMOVE_GROUP_FAILED = BASE + 20;
+ /** @hide */
+ public static final int REMOVE_GROUP_SUCCEEDED = BASE + 21;
/** @hide */
- public static final int REQUEST_CONNECTION_INFO = BASE + 21;
-
- /**
- * Message {@link android.os.Message#what} delivered on the application hander
- * in response to a {@link #requestConnectionInfo} call from the application.
- *
- * <p> Extract a {@link WifiP2pInfo} object by calling {@link #connectionInfoInResponse}
- * on the message object
- */
- public static final int RESPONSE_CONNECTION_INFO = BASE + 22;
+ public static final int REQUEST_PEERS = BASE + 22;
+ /** @hide */
+ public static final int RESPONSE_PEERS = BASE + 23;
/** @hide */
- public static final int REQUEST_GROUP_INFO = BASE + 23;
-
- /**
- * Message {@link android.os.Message#what} delivered on the application hander
- * in response to a {@link #requestGroupInfo} call from the application.
- *
- * <p> Extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
- * on the message object
- */
-
- public static final int RESPONSE_GROUP_INFO = BASE + 24;
+ public static final int REQUEST_CONNECTION_INFO = BASE + 24;
+ /** @hide */
+ public static final int RESPONSE_CONNECTION_INFO = BASE + 25;
/** @hide */
- public static final int WPS_PBC = BASE + 25;
+ public static final int REQUEST_GROUP_INFO = BASE + 26;
/** @hide */
- public static final int WPS_PIN = BASE + 26;
- /** @hide */
- public static final int WPS_PIN_AVAILABLE = BASE + 27;
+ public static final int RESPONSE_GROUP_INFO = BASE + 27;
/**
* Create a new WifiP2pManager instance. Applications use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link android.content.Context#WIFI_P2P_SERVICE Context.WIFI_P2P_SERVICE}.
* @param service the Binder interface
- * @param handler target for messages
* @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
* is a system private class.
*/
@@ -361,38 +275,182 @@
}
/**
- * A channel that connects the application handler to the Wifi framework.
- * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
- * by doing a call on {@link #initialize}
+ * Passed with {@link ActionListener#onFailure}.
+ * Indicates that the operation failed due to an internal error.
*/
- public class Channel {
- Channel(AsyncChannel c) {
- mAsyncChannel = c;
- }
- AsyncChannel mAsyncChannel;
+ public static final int ERROR = 0;
+
+ /**
+ * Passed with {@link ActionListener#onFailure}.
+ * Indicates that the operation failed because p2p is unsupported on the device.
+ */
+ public static final int P2P_UNSUPPORTED = 1;
+
+ /**
+ * Passed with {@link ActionListener#onFailure}.
+ * Indicates that the operation failed because the framework is busy and
+ * unable to service the request
+ */
+ public static final int BUSY = 2;
+
+ /** Interface for callback invocation when framework channel is lost */
+ public interface ChannelListener {
+ /**
+ * The channel to the framework has been disconnected.
+ * Application could try re-initializing using {@link #initialize}
+ */
+ public void onChannelDisconnected();
+ }
+
+ /** Interface for callback invocation on an application action */
+ public interface ActionListener {
+ /** The operation succeeded */
+ public void onSuccess();
+ /**
+ * The operation failed
+ * @param reason The reason for failure could be one of {@link #P2P_UNSUPPORTED},
+ * {@link #ERROR} or {@link #BUSY}
+ */
+ public void onFailure(int reason);
+ }
+
+ /** Interface for callback invocation when peer list is available */
+ public interface PeerListListener {
+ /**
+ * The requested peer list is available
+ * @param peers List of available peers
+ */
+ public void onPeersAvailable(WifiP2pDeviceList peers);
+ }
+
+ /** Interface for callback invocation when connection info is available */
+ public interface ConnectionInfoListener {
+ /**
+ * The requested connection info is available
+ * @param info Wi-Fi p2p connection info
+ */
+ public void onConnectionInfoAvailable(WifiP2pInfo info);
+ }
+
+ /** Interface for callback invocation when group info is available */
+ public interface GroupInfoListener {
+ /**
+ * The requested p2p group info is available
+ * @param group Wi-Fi p2p group info
+ */
+ public void onGroupInfoAvailable(WifiP2pGroup group);
}
/**
- * Registers the application handler with the Wi-Fi framework. This function
+ * A channel that connects the application to the Wifi p2p framework.
+ * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
+ * by doing a call on {@link #initialize}
+ */
+ public static class Channel {
+ Channel(Looper looper, ChannelListener l) {
+ mAsyncChannel = new AsyncChannel();
+ mHandler = new P2pHandler(looper);
+ mChannelListener = l;
+ }
+ private ChannelListener mChannelListener;
+ private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
+ private Object mListenerMapLock = new Object();
+ private int mListenerKey = 0;
+
+ AsyncChannel mAsyncChannel;
+ P2pHandler mHandler;
+ class P2pHandler extends Handler {
+ P2pHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ Object listener = getListener(message.arg2);
+ switch (message.what) {
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelDisconnected();
+ mChannelListener = null;
+ }
+ break;
+ /* ActionListeners grouped together */
+ case WifiP2pManager.DISCOVER_PEERS_FAILED:
+ case WifiP2pManager.CONNECT_FAILED:
+ case WifiP2pManager.CANCEL_CONNECT_FAILED:
+ case WifiP2pManager.CREATE_GROUP_FAILED:
+ case WifiP2pManager.REMOVE_GROUP_FAILED:
+ if (listener != null) {
+ ((ActionListener) listener).onFailure(message.arg1);
+ }
+ break;
+ /* ActionListeners grouped together */
+ case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED:
+ case WifiP2pManager.CONNECT_SUCCEEDED:
+ case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED:
+ case WifiP2pManager.CREATE_GROUP_SUCCEEDED:
+ case WifiP2pManager.REMOVE_GROUP_SUCCEEDED:
+ if (listener != null) {
+ ((ActionListener) listener).onSuccess();
+ }
+ break;
+ case WifiP2pManager.RESPONSE_PEERS:
+ WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj;
+ if (listener != null) {
+ ((PeerListListener) listener).onPeersAvailable(peers);
+ }
+ break;
+ case WifiP2pManager.RESPONSE_CONNECTION_INFO:
+ WifiP2pInfo wifiP2pInfo = (WifiP2pInfo) message.obj;
+ if (listener != null) {
+ ((ConnectionInfoListener) listener).onConnectionInfoAvailable(wifiP2pInfo);
+ }
+ break;
+ case WifiP2pManager.RESPONSE_GROUP_INFO:
+ WifiP2pGroup group = (WifiP2pGroup) message.obj;
+ if (listener != null) {
+ ((GroupInfoListener) listener).onGroupInfoAvailable(group);
+ }
+ break;
+ default:
+ Log.d(TAG, "Ignored " + message);
+ break;
+ }
+ }
+ }
+
+ int putListener(Object listener) {
+ if (listener == null) return 0;
+ int key;
+ synchronized (mListenerMapLock) {
+ key = mListenerKey++;
+ mListenerMap.put(key, listener);
+ }
+ return key;
+ }
+
+ Object getListener(int key) {
+ synchronized (mListenerMapLock) {
+ return mListenerMap.remove(key);
+ }
+ }
+ }
+
+ /**
+ * Registers the application with the Wi-Fi framework. This function
* must be the first to be called before any p2p operations are performed.
*
- * <p class="note"><strong>Note:</strong>
- * The handler registered with the framework should only handle messages
- * with {@link android.os.Message#what} values defined in this file. Adding application
- * specific private {@link android.os.Message#what} types should be done on a seperate handler
- *
* @param srcContext is the context of the source
- * @param srcHandler is the handler on which the source will receive message responses
- * asynchronously
+ * @param srcLooper is the Looper on which the callbacks are receivied
+ * @param listener for callback at loss of framework communication. Can be null.
* @return Channel instance that is necessary for performing any further p2p operations
*/
- public Channel initialize(Context srcContext, Handler srcHandler) {
+ public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
Messenger messenger = getMessenger();
if (messenger == null) return null;
- AsyncChannel asyncChannel = new AsyncChannel();
- Channel c = new Channel(asyncChannel);
- if (asyncChannel.connectSync(srcContext, srcHandler, messenger)
+ Channel c = new Channel(srcLooper, listener);
+ if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
== AsyncChannel.STATUS_SUCCESSFUL) {
return c;
} else {
@@ -425,30 +483,32 @@
* for the purpose of establishing a connection.
*
* <p> The function call immediately returns after sending a discovery request
- * to the framework. The application handler is notified of a success or failure to initiate
- * discovery with {@link #DISCOVER_PEERS_SUCCEEDED} or {@link #DISCOVER_PEERS_FAILED}.
+ * to the framework. The application is notified of a success or failure to initiate
+ * discovery through listener callbacks {@link ActionListener#onSuccess} or
+ * {@link ActionListener#onFailure}.
*
* <p> The discovery remains active until a connection is initiated or
* a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
* determine when the framework notifies of a change as peers are discovered.
*
* <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
- * can request for the list of peers using {@link #requestPeers} which will deliver a
- * {@link #RESPONSE_PEERS} message on the application handler. The application can then
- * extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
- * on the message.
+ * can request for the list of peers using {@link #requestPeers}.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callbacks on success or failure. Can be null.
*/
- public void discoverPeers(Channel c) {
+ public void discoverPeers(Channel c, ActionListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(DISCOVER_PEERS);
+ c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
}
/**
* Start a p2p connection to a device with the specified configuration.
*
* <p> The function call immediately returns after sending a connection request
- * to the framework. The application handler is notified of a success or failure to initiate
- * connectivity with {@link #CONNECT_SUCCEEDED} or {@link #CONNECT_FAILED}.
+ * to the framework. The application is notified of a success or failure to initiate
+ * connect through listener callbacks {@link ActionListener#onSuccess} or
+ * {@link ActionListener#onFailure}.
*
* <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
* determine when the framework notifies of a change in connectivity.
@@ -460,100 +520,102 @@
* a p2p group with {@link #createGroup}, an invitation to join the group is sent to
* the peer device.
*
- * @param config options as described in {@link WifiP2pConfig} class.
+ * @param c is the channel created at {@link #initialize}
+ * @param config options as described in {@link WifiP2pConfig} class
+ * @param listener for callbacks on success or failure. Can be null.
*/
- public void connect(Channel c, WifiP2pConfig config) {
+ public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(CONNECT, config);
+ c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);
+ }
+
+ /**
+ * Cancel any ongoing p2p group negotiation
+ *
+ * <p> The function call immediately returns after sending a connection cancellation request
+ * to the framework. The application is notified of a success or failure to initiate
+ * cancellation through listener callbacks {@link ActionListener#onSuccess} or
+ * {@link ActionListener#onFailure}.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callbacks on success or failure. Can be null.
+ */
+ public void cancelConnect(Channel c, ActionListener listener) {
+ if (c == null) return;
+ c.mAsyncChannel.sendMessage(CANCEL_CONNECT, 0, c.putListener(listener));
}
/**
* Create a p2p group with the current device as the group owner. This essentially creates
* an access point that can accept connections from legacy clients as well as other p2p
* devices.
- * <p> For p2p operation, this would normally not be used unless the current device needs
+ *
+ * <p class="note"><strong>Note:</strong>
+ * This function would normally not be used unless the current device needs
* to form a p2p connection with a legacy client
*
* <p> The function call immediately returns after sending a group creation request
- * to the framework. The application handler is notified of a success or failure to create
- * group with {@link #CREATE_GROUP_SUCCEEDED} or {@link #CREATE_GROUP_FAILED}.
+ * to the framework. The application is notified of a success or failure to initiate
+ * group creation through listener callbacks {@link ActionListener#onSuccess} or
+ * {@link ActionListener#onFailure}.
*
- * <p> Application can request for the group details with {@link #requestGroupInfo} which will
- * deliver a {@link #RESPONSE_GROUP_INFO} message on the application handler. The application
- * can then extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
- * on the message.
+ * <p> Application can request for the group details with {@link #requestGroupInfo}.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callbacks on success or failure. Can be null.
*/
- public void createGroup(Channel c) {
+ public void createGroup(Channel c, ActionListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(CREATE_GROUP);
+ c.mAsyncChannel.sendMessage(CREATE_GROUP, 0, c.putListener(listener));
}
/**
* Remove the current p2p group.
*
* <p> The function call immediately returns after sending a group removal request
- * to the framework. The application handler is notified of a success or failure to remove
- * a group with {@link #REMOVE_GROUP_SUCCEEDED} or {@link #REMOVE_GROUP_FAILED}.
+ * to the framework. The application is notified of a success or failure to initiate
+ * group removal through listener callbacks {@link ActionListener#onSuccess} or
+ * {@link ActionListener#onFailure}.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callbacks on success or failure. Can be null.
*/
- public void removeGroup(Channel c) {
+ public void removeGroup(Channel c, ActionListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(REMOVE_GROUP);
+ c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
}
/**
- * Request the current list of peers. This returns a {@link #RESPONSE_PEERS} on the application
- * handler. The {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is
- * available. Use {@link #peersInResponse} to extract {@link WifiP2pDeviceList} from the message
+ * Request the current list of peers.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callback when peer list is available. Can be null.
*/
- public void requestPeers(Channel c) {
+ public void requestPeers(Channel c, PeerListListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(REQUEST_PEERS);
+ c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
}
/**
- * Upon receiving a {@link #RESPONSE_PEERS} on the application handler, an application
- * can extract the peer device list using this function.
+ * Request device connection info.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callback when connection info is available. Can be null.
*/
- public WifiP2pDeviceList peersInResponse(Message msg) {
- return (WifiP2pDeviceList) msg.obj;
- }
-
- /**
- * Request device connection info. This returns a {@link #RESPONSE_CONNECTION_INFO} on
- * the application handler. The {@link #RESPONSE_CONNECTION_INFO} message on the handler
- * indicates that connection info is available. Use {@link #connectionInfoInResponse} to
- * extract {@link WifiP2pInfo} from the message.
- */
- public void requestConnectionInfo(Channel c) {
+ public void requestConnectionInfo(Channel c, ConnectionInfoListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO);
+ c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO, 0, c.putListener(listener));
}
/**
- * Upon receiving a {@link #RESPONSE_CONNECTION_INFO} on the application handler, an application
- * can extract the connection info using this function.
+ * Request p2p group info.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callback when group info is available. Can be null.
*/
- public WifiP2pInfo connectionInfoInResponse(Message msg) {
- return (WifiP2pInfo) msg.obj;
- }
-
- /**
- * Request p2p group info. This returns a {@link #RESPONSE_GROUP_INFO} on
- * the application handler. The {@link #RESPONSE_GROUP_INFO} message on the handler
- * indicates that group info is available. Use {@link #groupInfoInResponse} to
- * extract {@link WifiP2pGroup} from the message.
- */
- public void requestGroupInfo(Channel c) {
+ public void requestGroupInfo(Channel c, GroupInfoListener listener) {
if (c == null) return;
- c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO);
- }
-
- /**
- * Upon receiving a {@link #RESPONSE_GROUP_INFO} on the application handler, an application
- * can extract the group info using this function.
- */
- public WifiP2pGroup groupInfoInResponse(Message msg) {
- return (WifiP2pGroup) msg.obj;
+ c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO, 0, c.putListener(listener));
}
/**
@@ -571,36 +633,4 @@
}
}
- /**
- * Setup DNS connectivity on the current process to the connected Wi-Fi p2p peers
- *
- * @return -1 on failure
- * @hide
- */
- public int startPeerCommunication() {
- IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
- try {
- return cm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, "p2p", new Binder());
- } catch (RemoteException e) {
- return -1;
- }
- }
-
- /**
- * Tear down connectivity to the connected Wi-Fi p2p peers
- *
- * @return -1 on failure
- * @hide
- */
- public int stopPeerCommunication() {
- IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
- try {
- return cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, "p2p");
- } catch (RemoteException e) {
- return -1;
- }
- }
-
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 2f7b927..1b02774 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -41,9 +41,7 @@
import android.net.wifi.WifiMonitor;
import android.net.wifi.WifiNative;
import android.net.wifi.WifiStateMachine;
-import android.net.wifi.Wps;
-import android.net.wifi.Wps.Setup;
-import android.net.wifi.p2p.WifiP2pDevice.Status;
+import android.net.wifi.WpsInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -61,6 +59,7 @@
import android.widget.EditText;
import com.android.internal.R;
+import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
@@ -134,11 +133,14 @@
/* Airplane mode changed */
private static final int AIRPLANE_MODE_CHANGED = BASE + 6;
+ /* Emergency callback mode */
+ private static final int EMERGENCY_CALLBACK_MODE = BASE + 7;
+ private static final int WPS_PBC = BASE + 8;
+ private static final int WPS_PIN = BASE + 9;
private final boolean mP2pSupported;
- private final String mDeviceType;
- private String mDeviceName;
- private String mDeviceAddress;
+
+ private WifiP2pDevice mThisDevice = new WifiP2pDevice();
/* When a group has been explicitly created by an app, we persist the group
* even after all clients have been disconnected until an explicit remove
@@ -161,9 +163,9 @@
mP2pSupported = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_DIRECT);
- mDeviceType = mContext.getResources().getString(
+ mThisDevice.primaryDeviceType = mContext.getResources().getString(
com.android.internal.R.string.config_wifi_p2p_device_type);
- mDeviceName = getDefaultDeviceName();
+ mThisDevice.deviceName = getDefaultDeviceName();
mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
mP2pStateMachine.start();
@@ -172,6 +174,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mContext.registerReceiver(new WifiStateReceiver(), filter);
@@ -185,14 +188,19 @@
private class WifiStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ String action = intent.getAction();
+ if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_DISABLED);
- } else if (intent.getAction().equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+ } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
WifiManager.WIFI_AP_STATE_DISABLED);
- } else if (intent.getAction().equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+ } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
mP2pStateMachine.sendMessage(AIRPLANE_MODE_CHANGED);
+ } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ if (intent.getBooleanExtra("phoneinECMState", false) == true) {
+ mP2pStateMachine.sendMessage(EMERGENCY_CALLBACK_MODE);
+ }
}
}
}
@@ -341,6 +349,10 @@
replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
WifiP2pManager.BUSY);
break;
+ case WifiP2pManager.CANCEL_CONNECT:
+ replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
+ WifiP2pManager.BUSY);
+ break;
case WifiP2pManager.CREATE_GROUP:
replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
WifiP2pManager.BUSY);
@@ -361,6 +373,9 @@
case AIRPLANE_MODE_CHANGED:
if (isAirplaneModeOn()) sendMessage(WifiP2pManager.DISABLE_P2P);
break;
+ case EMERGENCY_CALLBACK_MODE:
+ sendMessage(WifiP2pManager.DISABLE_P2P);
+ break;
// Ignore
case WIFI_DISABLE_USER_ACCEPT:
case WIFI_DISABLE_USER_REJECT:
@@ -398,6 +413,10 @@
replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
+ case WifiP2pManager.CANCEL_CONNECT:
+ replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
+ WifiP2pManager.P2P_UNSUPPORTED);
+ break;
case WifiP2pManager.CREATE_GROUP:
replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
@@ -644,7 +663,7 @@
break;
case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
WifiP2pDevice device = (WifiP2pDevice) message.obj;
- if (mDeviceAddress.equals(device.deviceAddress)) break;
+ if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
mPeers.update(device);
sendP2pPeersChangedBroadcast();
break;
@@ -671,7 +690,7 @@
// do nothing if p2pConnect did not return a pin
}
}
- updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.INVITED);
+ updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.INVITED);
sendP2pPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
transitionTo(mGroupNegotiationState);
@@ -694,7 +713,7 @@
P2pStateMachine.this, mGroup.getInterface());
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
WifiP2pDevice groupOwner = mGroup.getOwner();
- updateDeviceStatus(groupOwner.deviceAddress, Status.CONNECTED);
+ updateDeviceStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
sendP2pPeersChangedBroadcast();
}
transitionTo(mGroupCreatedState);
@@ -771,7 +790,7 @@
case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
if (DBG) logd(getName() + " go failure");
- updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.FAILED);
+ updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.FAILED);
mSavedConnectConfig = null;
sendP2pPeersChangedBroadcast();
transitionTo(mInactiveState);
@@ -779,7 +798,7 @@
case GROUP_NEGOTIATION_TIMED_OUT:
if (mGroupNegotiationTimeoutIndex == message.arg1) {
if (DBG) logd("Group negotiation timed out");
- updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.FAILED);
+ updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.FAILED);
mSavedConnectConfig = null;
sendP2pPeersChangedBroadcast();
transitionTo(mInactiveState);
@@ -790,6 +809,14 @@
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.BUSY);
break;
+ case WifiP2pManager.CANCEL_CONNECT:
+ if (WifiNative.p2pCancelConnect()) {
+ replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
+ } else {
+ replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
+ WifiP2pManager.ERROR);
+ }
+ break;
default:
return NOT_HANDLED;
}
@@ -803,6 +830,8 @@
if (DBG) logd(getName());
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+ updateThisDevice(WifiP2pDevice.CONNECTED);
+
//DHCP server has already been started if I am a group owner
if (mGroup.isGroupOwner()) {
setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
@@ -820,7 +849,7 @@
String deviceAddress = getDeviceAddress(interfaceAddress);
if (deviceAddress != null) {
mGroup.addClient(deviceAddress);
- updateDeviceStatus(deviceAddress, Status.CONNECTED);
+ updateDeviceStatus(deviceAddress, WifiP2pDevice.CONNECTED);
if (DBG) logd(getName() + " ap sta connected");
sendP2pPeersChangedBroadcast();
} else {
@@ -831,7 +860,7 @@
interfaceAddress = (String) message.obj;
deviceAddress = getDeviceAddress(interfaceAddress);
if (deviceAddress != null) {
- updateDeviceStatus(deviceAddress, Status.AVAILABLE);
+ updateDeviceStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
if (mGroup.removeClient(deviceAddress)) {
if (DBG) logd("Removed client " + deviceAddress);
if (!mPersistGroup && mGroup.isClientListEmpty()) {
@@ -876,7 +905,7 @@
boolean changed = false;
for (WifiP2pDevice d : mPeers.getDeviceList()) {
if (devices.contains(d) || mGroup.getOwner().equals(d)) {
- d.status = Status.AVAILABLE;
+ d.status = WifiP2pDevice.AVAILABLE;
changed = true;
}
}
@@ -914,7 +943,7 @@
WifiP2pConfig config = (WifiP2pConfig) message.obj;
logd("Inviting device : " + config.deviceAddress);
if (WifiNative.p2pInvite(mGroup, config.deviceAddress)) {
- updateDeviceStatus(config.deviceAddress, Status.INVITED);
+ updateDeviceStatus(config.deviceAddress, WifiP2pDevice.INVITED);
sendP2pPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
} else {
@@ -935,10 +964,10 @@
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
Slog.e(TAG, "Duplicate group creation event notice, ignore");
break;
- case WifiP2pManager.WPS_PBC:
+ case WPS_PBC:
WifiNative.wpsPbc();
break;
- case WifiP2pManager.WPS_PIN:
+ case WPS_PIN:
WifiNative.wpsPin((String) message.obj);
break;
default:
@@ -948,6 +977,7 @@
}
public void exit() {
+ updateThisDevice(WifiP2pDevice.AVAILABLE);
setWifiP2pInfoOnGroupTermination();
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
sendP2pConnectionChangedBroadcast();
@@ -967,6 +997,13 @@
mContext.sendStickyBroadcast(intent);
}
+ private void sendThisDeviceChangedBroadcast() {
+ final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
+ mContext.sendStickyBroadcast(intent);
+ }
+
private void sendP2pPeersChangedBroadcast() {
final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1036,7 +1073,7 @@
private void notifyP2pGoNegotationRequest(WifiP2pConfig config) {
Resources r = Resources.getSystem();
- Wps wps = config.wps;
+ WpsInfo wps = config.wps;
final View textEntryView = LayoutInflater.from(mContext)
.inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null);
final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin);
@@ -1049,9 +1086,9 @@
if (DBG) logd(getName() + " connect " + pin.getText());
if (pin.getVisibility() == View.GONE) {
- mSavedGoNegotiationConfig.wps.setup = Setup.PBC;
+ mSavedGoNegotiationConfig.wps.setup = WpsInfo.PBC;
} else {
- mSavedGoNegotiationConfig.wps.setup = Setup.KEYPAD;
+ mSavedGoNegotiationConfig.wps.setup = WpsInfo.KEYPAD;
mSavedGoNegotiationConfig.wps.pin = pin.getText().toString();
}
sendMessage(WifiP2pManager.CONNECT, mSavedGoNegotiationConfig);
@@ -1067,7 +1104,7 @@
})
.create();
- if (wps.setup == Setup.PBC) {
+ if (wps.setup == WpsInfo.PBC) {
pin.setVisibility(View.GONE);
dialog.setMessage(r.getString(R.string.wifi_p2p_pbc_go_negotiation_request_message,
config.deviceAddress));
@@ -1092,7 +1129,7 @@
.setPositiveButton(r.getString(R.string.ok), new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (DBG) logd(getName() + " wps_pbc");
- sendMessage(WifiP2pManager.WPS_PBC);
+ sendMessage(WPS_PBC);
}
})
.setNegativeButton(r.getString(R.string.cancel), null)
@@ -1118,7 +1155,7 @@
.setPositiveButton(r.getString(R.string.ok), new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (DBG) logd(getName() + " wps_pin");
- sendMessage(WifiP2pManager.WPS_PIN, pin.getText().toString());
+ sendMessage(WPS_PIN, pin.getText().toString());
}
})
.setNegativeButton(r.getString(R.string.cancel), null)
@@ -1161,7 +1198,7 @@
dialog.show();
}
- private void updateDeviceStatus(String deviceAddress, Status status) {
+ private void updateDeviceStatus(String deviceAddress, int status) {
for (WifiP2pDevice d : mPeers.getDeviceList()) {
if (d.deviceAddress.equals(deviceAddress)) {
d.status = status;
@@ -1206,28 +1243,50 @@
private void initializeP2pSettings() {
WifiNative.setPersistentReconnect(true);
- WifiNative.setDeviceName(mDeviceName);
- WifiNative.setDeviceType(mDeviceType);
+ WifiNative.setDeviceName(mThisDevice.deviceName);
+ WifiNative.setDeviceType(mThisDevice.primaryDeviceType);
- mDeviceAddress = WifiNative.p2pGetDeviceAddress();
- if (DBG) Slog.d(TAG, "DeviceAddress: " + mDeviceAddress);
+ mThisDevice.deviceAddress = WifiNative.p2pGetDeviceAddress();
+ updateThisDevice(WifiP2pDevice.AVAILABLE);
+ if (DBG) Slog.d(TAG, "DeviceAddress: " + mThisDevice.deviceAddress);
+ }
+
+ private void updateThisDevice(int status) {
+ mThisDevice.status = status;
+ sendThisDeviceChangedBroadcast();
}
//State machine initiated requests can have replyTo set to null indicating
//there are no recepients, we ignore those reply actions
private void replyToMessage(Message msg, int what) {
if (msg.replyTo == null) return;
- mReplyChannel.replyToMessage(msg, what);
+ Message dstMsg = obtainMessage(msg);
+ dstMsg.what = what;
+ mReplyChannel.replyToMessage(msg, dstMsg);
}
private void replyToMessage(Message msg, int what, int arg1) {
if (msg.replyTo == null) return;
- mReplyChannel.replyToMessage(msg, what, arg1);
+ Message dstMsg = obtainMessage(msg);
+ dstMsg.what = what;
+ dstMsg.arg1 = arg1;
+ mReplyChannel.replyToMessage(msg, dstMsg);
}
private void replyToMessage(Message msg, int what, Object obj) {
if (msg.replyTo == null) return;
- mReplyChannel.replyToMessage(msg, what, obj);
+ Message dstMsg = obtainMessage(msg);
+ dstMsg.what = what;
+ dstMsg.obj = obj;
+ mReplyChannel.replyToMessage(msg, dstMsg);
+ }
+
+ /* arg2 on the source message has a hash code that needs to be retained in replies
+ * see WifiP2pManager for details */
+ private Message obtainMessage(Message srcMsg) {
+ Message msg = Message.obtain();
+ msg.arg2 = srcMsg.arg2;
+ return msg;
}
private void logd(String s) {