diff options
107 files changed, 4208 insertions, 1909 deletions
@@ -128,6 +128,8 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/display/IDisplayManagerCallback.aidl \ core/java/android/hardware/input/IInputManager.aidl \ core/java/android/hardware/input/IInputDevicesChangedListener.aidl \ + core/java/android/hardware/location/IFusedLocationHardware.aidl \ + core/java/android/hardware/location/IFusedLocationHardwareSink.aidl \ core/java/android/hardware/location/IGeofenceHardware.aidl \ core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \ core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \ @@ -232,12 +234,14 @@ LOCAL_SRC_FILES += \ keystore/java/android/security/IKeyChainService.aidl \ location/java/android/location/ICountryDetector.aidl \ location/java/android/location/ICountryListener.aidl \ + location/java/android/location/IFusedProvider.aidl \ location/java/android/location/IGeocodeProvider.aidl \ location/java/android/location/IGeofenceProvider.aidl \ location/java/android/location/IGpsStatusListener.aidl \ location/java/android/location/IGpsStatusProvider.aidl \ location/java/android/location/ILocationListener.aidl \ location/java/android/location/ILocationManager.aidl \ + location/java/android/location/IFusedGeofenceHardware.aidl \ location/java/android/location/IGpsGeofenceHardware.aidl \ location/java/android/location/INetInitiatedListener.aidl \ location/java/com/android/internal/location/ILocationProvider.aidl \ @@ -379,6 +383,7 @@ aidl_files := \ frameworks/base/location/java/android/location/Geofence.aidl \ frameworks/base/location/java/android/location/Location.aidl \ frameworks/base/location/java/android/location/LocationRequest.aidl \ + frameworks/base/location/java/android/location/FusedBatchOptions.aidl \ frameworks/base/location/java/com/android/internal/location/ProviderProperties.aidl \ frameworks/base/location/java/com/android/internal/location/ProviderRequest.aidl \ frameworks/base/telephony/java/android/telephony/ServiceState.aidl \ diff --git a/api/current.txt b/api/current.txt index d79a8c0..b9d51fd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -20716,6 +20716,7 @@ package android.provider { field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS"; field public static final java.lang.String ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS"; field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS"; + field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS"; field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS"; field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS"; field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS"; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4e6c3dc..c65f17e 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -16,14 +16,13 @@ package android.app; -import android.R; import android.os.BatteryStats; import android.os.IBinder; import com.android.internal.app.IUsageStats; +import com.android.internal.app.ProcessStats; import com.android.internal.os.PkgUsageStats; import com.android.internal.os.TransferPipe; import com.android.internal.util.FastPrintWriter; -import com.android.internal.util.MemInfoReader; import android.content.ComponentName; import android.content.Context; @@ -35,9 +34,7 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Point; import android.graphics.Rect; -import android.hardware.display.DisplayManagerGlobal; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -52,7 +49,6 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; -import android.view.Display; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -2253,7 +2249,7 @@ public class ActivityManager { PrintWriter pw = new FastPrintWriter(fout); dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName }); pw.println(); - dumpService(pw, fd, "procstats", new String[] { packageName }); + dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName }); pw.println(); dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName }); pw.println(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 9faaace..eb5c3e7 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1979,7 +1979,7 @@ class ContextImpl extends Context { " compatiblity info:" + container.getDisplayMetrics()); } if (compatInfo == null) { - compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; + compatInfo = packageInfo.getCompatibilityInfo(); } mDisplayAdjustments.setCompatibilityInfo(compatInfo); mDisplayAdjustments.setActivityToken(activityToken); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 17e8dd9..be831d7 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1527,9 +1527,26 @@ public class DevicePolicyManager { */ public boolean setDeviceOwner(String packageName) throws IllegalArgumentException, IllegalStateException { + return setDeviceOwner(packageName, null); + } + + /** + * @hide + * Sets the given package as the device owner. The package must already be installed and there + * shouldn't be an existing device owner registered, for this call to succeed. Also, this + * method must be called before the device is provisioned. + * @param packageName the package name of the application to be registered as the device owner. + * @param ownerName the human readable name of the institution that owns this device. + * @return whether the package was successfully registered as the device owner. + * @throws IllegalArgumentException if the package name is null or invalid + * @throws IllegalStateException if a device owner is already registered or the device has + * already been provisioned. + */ + public boolean setDeviceOwner(String packageName, String ownerName) + throws IllegalArgumentException, IllegalStateException { if (mService != null) { try { - return mService.setDeviceOwner(packageName); + return mService.setDeviceOwner(packageName, ownerName); } catch (RemoteException re) { Log.w(TAG, "Failed to set device owner"); } @@ -1581,4 +1598,16 @@ public class DevicePolicyManager { } return null; } + + /** @hide */ + public String getDeviceOwnerName() { + if (mService != null) { + try { + return mService.getDeviceOwnerName(); + } catch (RemoteException re) { + Log.w(TAG, "Failed to get device owner"); + } + } + return null; + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index b2a65bf..9659a91 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -98,7 +98,8 @@ interface IDevicePolicyManager { void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); - boolean setDeviceOwner(String packageName); + boolean setDeviceOwner(String packageName, String ownerName); boolean isDeviceOwner(String packageName); String getDeviceOwner(); + String getDeviceOwnerName(); } diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java index 81c0a6a..0aedecb 100644 --- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java +++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java @@ -152,6 +152,11 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Re-enable connectivity to a network after a {@link #teardown()}. */ diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 6318e38..1c28138 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -786,10 +786,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration // 2 most significant bits in screenLayout). setLayoutDirection(locale); } + if (delta.screenLayout != 0 && screenLayout != delta.screenLayout) { + changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; + setLayoutDirection(locale); + } if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) { - userSetLocale = true; changed |= ActivityInfo.CONFIG_LOCALE; + userSetLocale = true; } if (delta.touchscreen != TOUCHSCREEN_UNDEFINED && touchscreen != delta.touchscreen) { @@ -933,6 +937,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_LOCALE; changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; } + if (delta.screenLayout != 0 && screenLayout != delta.screenLayout) { + changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; + } if (delta.touchscreen != TOUCHSCREEN_UNDEFINED && touchscreen != delta.touchscreen) { changed |= ActivityInfo.CONFIG_TOUCHSCREEN; @@ -1005,7 +1012,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static boolean needNewResources(int configChanges, int interestingChanges) { return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0; } - + /** * @hide Return true if the sequence of 'other' is better than this. Assumes * that 'this' is your current sequence and 'other' is a new one you have diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java index a9e39c3..b234e34 100644..100755 --- a/core/java/android/database/DefaultDatabaseErrorHandler.java +++ b/core/java/android/database/DefaultDatabaseErrorHandler.java @@ -99,7 +99,7 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler { } Log.e(TAG, "deleting the database file: " + fileName); try { - new File(fileName).delete(); + SQLiteDatabase.deleteDatabase(new File(fileName)); } catch (Exception e) { /* print warning and ignore exception */ Log.w(TAG, "delete failed: " + e.getMessage()); diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl new file mode 100644 index 0000000..382c12c --- /dev/null +++ b/core/java/android/hardware/location/IFusedLocationHardware.aidl @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/license/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.location; + +import android.hardware.location.IFusedLocationHardwareSink; +import android.location.FusedBatchOptions; + +/** + * Fused Location hardware interface. + * This interface is the basic set of supported functionality by Fused Hardware + * modules that offer Location batching capabilities. + * + * @hide + */ +interface IFusedLocationHardware { + /** + * Registers a sink with the Location Hardware object. + * + * @param eventSink The sink to register. + */ + void registerSink(in IFusedLocationHardwareSink eventSink); + + /** + * Unregisters a sink with the Location Hardware object. + * + * @param eventSink The sink to unregister. + */ + void unregisterSink(in IFusedLocationHardwareSink eventSink); + + /** + * Provides access to the batch size available in Hardware. + * + * @return The batch size the hardware supports. + */ + int getSupportedBatchSize(); + + /** + * Requests the Hardware to start batching locations. + * + * @param id An Id associated with the request. + * @param batchOptions The options required for batching. + * + * @throws RuntimeException if the request Id exists. + */ + void startBatching(in int id, in FusedBatchOptions batchOptions); + + /** + * Requests the Hardware to stop batching for the given Id. + * + * @param id The request that needs to be stopped. + * @throws RuntimeException if the request Id is unknown. + */ + void stopBatching(in int id); + + /** + * Updates a batching operation in progress. + * + * @param id The Id of the operation to update. + * @param batchOptions The options to apply to the given operation. + * + * @throws RuntimeException if the Id of the request is unknown. + */ + void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions); + + /** + * Requests the most recent locations available in Hardware. + * This operation does not dequeue the locations, so still other batching + * events will continue working. + * + * @param batchSizeRequested The number of locations requested. + */ + void requestBatchOfLocations(in int batchSizeRequested); + + /** + * Flags if the Hardware supports injection of diagnostic data. + * + * @return True if data injection is supported, false otherwise. + */ + boolean supportsDiagnosticDataInjection(); + + /** + * Injects diagnostic data into the Hardware subsystem. + * + * @param data The data to inject. + * @throws RuntimeException if injection is not supported. + */ + void injectDiagnosticData(in String data); + + /** + * Flags if the Hardware supports injection of device context information. + * + * @return True if device context injection is supported, false otherwise. + */ + boolean supportsDeviceContextInjection(); + + /** + * Injects device context information into the Hardware subsystem. + * + * @param deviceEnabledContext The context to inject. + * @throws RuntimeException if injection is not supported. + */ + void injectDeviceContext(in int deviceEnabledContext); +} diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl new file mode 100644 index 0000000..a11d8ab --- /dev/null +++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/license/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.location; + +import android.location.Location; + +/** + * Fused Location hardware event sink interface. + * This interface defines the set of events that the FusedLocationHardware provides. + * + * @hide + */ +interface IFusedLocationHardwareSink { + /** + * Event generated when a batch of location information is available. + * + * @param locations The batch of location information available. + */ + void onLocationAvailable(in Location[] locations); + + /** + * Event generated from FLP HAL to provide diagnostic data to the platform. + * + * @param data The diagnostic data provided by FLP HAL. + */ + void onDiagnosticDataAvailable(in String data); +}
\ No newline at end of file diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java index 1165281..e87f84c 100644 --- a/core/java/android/net/BaseNetworkStateTracker.java +++ b/core/java/android/net/BaseNetworkStateTracker.java @@ -102,6 +102,11 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker { } @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + + @Override public boolean setRadio(boolean turnOn) { // Base tracker doesn't handle radios return true; diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java index 19d74ed..74c2c59 100644 --- a/core/java/android/net/CaptivePortalTracker.java +++ b/core/java/android/net/CaptivePortalTracker.java @@ -46,6 +46,7 @@ import android.telephony.CellInfoGsm; import android.telephony.CellInfoLte; import android.telephony.CellInfoWcdma; import android.telephony.TelephonyManager; +import android.text.TextUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -54,6 +55,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.Inet4Address; +import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import java.util.List; @@ -65,7 +67,7 @@ import com.android.internal.R; * @hide */ public class CaptivePortalTracker extends StateMachine { - private static final boolean DBG = false; + private static final boolean DBG = true; private static final String TAG = "CaptivePortalTracker"; private static final String DEFAULT_SERVER = "clients3.google.com"; @@ -301,6 +303,7 @@ public class CaptivePortalTracker extends StateMachine { } else { if (DBG) log("Not captive network " + mNetworkInfo); } + notifyPortalCheckCompleted(mNetworkInfo, captive); if (mDeviceProvisioned) { if (captive) { // Setup Wizard will assist the user in connecting to a captive @@ -331,12 +334,26 @@ public class CaptivePortalTracker extends StateMachine { return; } try { + if (DBG) log("notifyPortalCheckComplete: ni=" + info); mConnService.captivePortalCheckComplete(info); } catch(RemoteException e) { e.printStackTrace(); } } + private void notifyPortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + if (info == null) { + loge("notifyPortalCheckComplete on null"); + return; + } + try { + if (DBG) log("notifyPortalCheckCompleted: captive=" + isCaptivePortal + " ni=" + info); + mConnService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch(RemoteException e) { + e.printStackTrace(); + } + } + private boolean isActiveNetwork(NetworkInfo info) { try { NetworkInfo active = mConnService.getActiveNetworkInfo(); @@ -382,6 +399,12 @@ public class CaptivePortalTracker extends StateMachine { sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal, requestTimestamp, responseTimestamp); return isCaptivePortal; + } catch (SocketTimeoutException e) { + if (DBG) log("Probably a portal: exception " + e); + if (requestTimestamp != -1) { + sendFailedCaptivePortalCheckBroadcast(requestTimestamp); + } // else something went wrong with setting up the urlConnection + return true; } catch (IOException e) { if (DBG) log("Probably not a portal: exception " + e); if (requestTimestamp != -1) { @@ -415,6 +438,7 @@ public class CaptivePortalTracker extends StateMachine { private void setNotificationVisible(boolean visible) { // if it should be hidden and it is already hidden, then noop if (!visible && !mNotificationShown) { + if (DBG) log("setNotivicationVisible: false and not shown, so noop"); return; } @@ -426,12 +450,14 @@ public class CaptivePortalTracker extends StateMachine { CharSequence title; CharSequence details; int icon; + String url = null; switch (mNetworkInfo.getType()) { case ConnectivityManager.TYPE_WIFI: title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, mNetworkInfo.getExtraInfo()); icon = R.drawable.stat_notify_wifi_in_range; + url = mUrl; break; case ConnectivityManager.TYPE_MOBILE: title = r.getString(R.string.network_available_sign_in, 0); @@ -439,12 +465,24 @@ public class CaptivePortalTracker extends StateMachine { // name has been added to it details = mTelephonyManager.getNetworkOperatorName(); icon = R.drawable.stat_notify_rssi_in_range; + try { + url = mConnService.getMobileProvisioningUrl(); + if (TextUtils.isEmpty(url)) { + url = mConnService.getMobileRedirectedProvisioningUrl(); + } + } catch(RemoteException e) { + e.printStackTrace(); + } + if (TextUtils.isEmpty(url)) { + url = mUrl; + } break; default: title = r.getString(R.string.network_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, mNetworkInfo.getExtraInfo()); icon = R.drawable.stat_notify_rssi_in_range; + url = mUrl; break; } @@ -452,15 +490,17 @@ public class CaptivePortalTracker extends StateMachine { notification.when = 0; notification.icon = icon; notification.flags = Notification.FLAG_AUTO_CANCEL; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl)); + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); notification.tickerText = title; notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); + if (DBG) log("setNotivicationVisible: make visible"); notificationManager.notify(NOTIFICATION_ID, 1, notification); } else { + if (DBG) log("setNotivicationVisible: cancel notification"); notificationManager.cancel(NOTIFICATION_ID, 1); } mNotificationShown = visible; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1dbe34e..1b418fa 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1324,6 +1324,25 @@ public class ConnectivityManager { } /** + * Signal that the captive portal check on the indicated network + * is complete and whether its a captive portal or not. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * @param isCaptivePortal true/false. + * + * <p>This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * {@hide} + */ + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + try { + mService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch (RemoteException e) { + } + } + + /** * Supply the backend messenger for a network tracker * * @param type NetworkType to set @@ -1401,7 +1420,7 @@ public class ConnectivityManager { } /** - * Get the carrier provisioning url. + * Get the mobile provisioning url. * {@hide} */ public String getMobileProvisioningUrl() { @@ -1411,4 +1430,16 @@ public class ConnectivityManager { } return null; } + + /** + * Get the mobile redirected provisioning url. + * {@hide} + */ + public String getMobileRedirectedProvisioningUrl() { + try { + return mService.getMobileRedirectedProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java index 15a81f3..ee738fd 100644 --- a/core/java/android/net/DummyDataStateTracker.java +++ b/core/java/android/net/DummyDataStateTracker.java @@ -120,10 +120,16 @@ public class DummyDataStateTracker implements NetworkStateTracker { return true; } + @Override public void captivePortalCheckComplete() { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Record the detailed state of a network, and if it is a * change from the previous state, send a notification to diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index 7b803a8..7999c66 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -280,6 +280,11 @@ public class EthernetDataTracker implements NetworkStateTracker { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Turn the wireless radio off for a network. * @param turnOn {@code true} to turn the radio on, {@code false} diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b0f7fc6..992ec37 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -134,6 +134,8 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); + void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); + void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); @@ -141,4 +143,6 @@ interface IConnectivityManager int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); String getMobileProvisioningUrl(); + + String getMobileRedirectedProvisioningUrl(); } diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 54273ee..e4fd312 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -40,6 +40,7 @@ import com.android.internal.util.AsyncChannel; import java.io.CharArrayWriter; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicBoolean; /** * Track the state of mobile data connectivity. This is done by @@ -75,6 +76,8 @@ public class MobileDataStateTracker implements NetworkStateTracker { private Handler mHandler; private AsyncChannel mDataConnectionTrackerAc; + private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false); + /** * Create a new MobileDataStateTracker * @param netType the ConnectivityManager network type @@ -377,6 +380,15 @@ public class MobileDataStateTracker implements NetworkStateTracker { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { + // Captive portal change enable/disable failing fast + setEnableFailFastMobileData( + isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); + } + } + /** * Record the detailed state of a network, and if it is a * change from the previous state, send a notification to diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index cf77a1c..9ed7533 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -144,6 +144,11 @@ public interface NetworkStateTracker { public void captivePortalCheckComplete(); /** + * Captive portal check has completed + */ + public void captivePortalCheckCompleted(boolean isCaptive); + + /** * Turn the wireless radio off for a network. * @param turnOn {@code true} to turn the radio on, {@code false} */ diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index ffa7d7e..3f7e3ef 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -188,7 +188,8 @@ public final class ApduServiceInfo implements Parcelable { currentGroup != null) { final TypedArray a = res.obtainAttributes(attrs, com.android.internal.R.styleable.AidFilter); - String aid = a.getString(com.android.internal.R.styleable.AidFilter_name); + String aid = a.getString(com.android.internal.R.styleable.AidFilter_name). + toUpperCase(); if (isValidAid(aid) && !currentGroup.aids.contains(aid)) { currentGroup.aids.add(aid); mAids.add(aid); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 12646bd..38ffb96 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -155,6 +155,7 @@ public abstract class BatteryStats implements Parcelable { private static final String BATTERY_LEVEL_DATA = "lv"; private static final String WIFI_DATA = "wfl"; private static final String MISC_DATA = "m"; + private static final String HISTORY_DATA = "h"; private static final String SCREEN_BRIGHTNESS_DATA = "br"; private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt"; private static final String SIGNAL_SCANNING_TIME_DATA = "sst"; @@ -2390,7 +2391,7 @@ public abstract class BatteryStats implements Parcelable { while (getNextHistoryLocked(rec)) { pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); pw.print(0); pw.print(','); - pw.print("h"); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); hprinter.printNextItemCheckin(pw, rec, now); pw.println(); } diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 97ea99d..4d48fd4 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -17,10 +17,17 @@ package android.os; import android.util.Log; +import android.util.Slog; + +import libcore.io.ErrnoException; +import libcore.io.IoUtils; +import libcore.io.Libcore; +import libcore.io.OsConstants; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -58,9 +65,84 @@ public class FileUtils { /** Regular expression for safe filenames: no spaces or metacharacters */ private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); - public static native int setPermissions(String file, int mode, int uid, int gid); + /** + * Set owner and mode of of given {@link File}. + * + * @param mode to apply through {@code chmod} + * @param uid to apply through {@code chown}, or -1 to leave unchanged + * @param gid to apply through {@code chown}, or -1 to leave unchanged + * @return 0 on success, otherwise errno. + */ + public static int setPermissions(File path, int mode, int uid, int gid) { + return setPermissions(path.getAbsolutePath(), mode, uid, gid); + } + + /** + * Set owner and mode of of given path. + * + * @param mode to apply through {@code chmod} + * @param uid to apply through {@code chown}, or -1 to leave unchanged + * @param gid to apply through {@code chown}, or -1 to leave unchanged + * @return 0 on success, otherwise errno. + */ + public static int setPermissions(String path, int mode, int uid, int gid) { + try { + Libcore.os.chmod(path, mode); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to chmod(" + path + "): " + e); + return e.errno; + } + + if (uid >= 0 || gid >= 0) { + try { + Libcore.os.chown(path, uid, gid); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to chown(" + path + "): " + e); + return e.errno; + } + } + + return 0; + } + + /** + * Set owner and mode of of given {@link FileDescriptor}. + * + * @param mode to apply through {@code chmod} + * @param uid to apply through {@code chown}, or -1 to leave unchanged + * @param gid to apply through {@code chown}, or -1 to leave unchanged + * @return 0 on success, otherwise errno. + */ + public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) { + try { + Libcore.os.fchmod(fd, mode); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to fchmod(): " + e); + return e.errno; + } - public static native int getUid(String file); + if (uid >= 0 || gid >= 0) { + try { + Libcore.os.fchown(fd, uid, gid); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to fchown(): " + e); + return e.errno; + } + } + + return 0; + } + + /** + * Return owning UID of given path, otherwise -1. + */ + public static int getUid(String path) { + try { + return Libcore.os.stat(path).st_uid; + } catch (ErrnoException e) { + return -1; + } + } /** returns the FAT file system volume ID for the volume mounted * at the given mount point, or -1 for failure diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index ab0543d..cf9ddb3 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -100,12 +100,6 @@ public class Process { public static final int DRM_UID = 1019; /** - * Defines the GID for the group that allows write access to the SD card. - * @hide - */ - public static final int SDCARD_RW_GID = 1015; - - /** * Defines the UID/GID for the group that controls VPN services. * @hide */ @@ -130,11 +124,18 @@ public class Process { public static final int MEDIA_RW_GID = 1023; /** + * Access to installed package details + * @hide + */ + public static final int PACKAGE_INFO_GID = 1032; + + /** * Defines the start of a range of UIDs (and GIDs), going from this * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning * to applications. */ public static final int FIRST_APPLICATION_UID = 10000; + /** * Last of application-specific UIDs starting at * {@link #FIRST_APPLICATION_UID}. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 130123f..585115a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -33,6 +33,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; import android.database.SQLException; +import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.Uri; import android.net.wifi.WifiManager; @@ -643,6 +644,23 @@ public final class Settings { "android.settings.NFCSHARING_SETTINGS"; /** + * Activity Action: Show NFC Tap & Pay settings + * <p> + * This shows UI that allows the user to configure Tap&Pay + * settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_NFC_PAYMENT_SETTINGS = + "android.settings.NFC_PAYMENT_SETTINGS"; + + /** * Activity Action: Show Daydream settings. * <p> * In some cases, a matching Activity may not exist, so ensure you @@ -737,6 +755,10 @@ public final class Settings { private static final String TAG = "Settings"; private static final boolean LOCAL_LOGV = false; + // Lock ensures that when enabling/disabling the master location switch, we don't end up + // with a partial enable/disable state in multi-threaded situations. + private static final Object mLocationSettingsLock = new Object(); + public static class SettingNotFoundException extends AndroidException { public SettingNotFoundException(String msg) { super(msg); @@ -4303,6 +4325,20 @@ public final class Settings { } /** + * Helper method for determining if the location master switch is enabled. + * @param cr the content resolver to use + * @return true if the master switch is enabled + * @hide + */ + public static final boolean isLocationMasterSwitchEnabled(ContentResolver cr) { + int uid = UserHandle.myUserId(); + synchronized (mLocationSettingsLock) { + return isLocationProviderEnabledForUser(cr, LocationManager.NETWORK_PROVIDER, uid) + || isLocationProviderEnabledForUser(cr, LocationManager.GPS_PROVIDER, uid); + } + } + + /** * Helper method for determining if a location provider is enabled. * @param cr the content resolver to use * @param provider the location provider to query @@ -4328,6 +4364,23 @@ public final class Settings { } /** + * Thread-safe method for enabling or disabling the location master switch. + * + * @param cr the content resolver to use + * @param enabled true if master switch should be enabled + * @hide + */ + public static final void setLocationMasterSwitchEnabled(ContentResolver cr, + boolean enabled) { + int uid = UserHandle.myUserId(); + synchronized (mLocationSettingsLock) { + setLocationProviderEnabledForUser(cr, LocationManager.GPS_PROVIDER, enabled, uid); + setLocationProviderEnabledForUser(cr, LocationManager.NETWORK_PROVIDER, enabled, + uid); + } + } + + /** * Thread-safe method for enabling or disabling a single location provider. * @param cr the content resolver to use * @param provider the location provider to enable or disable @@ -4337,16 +4390,18 @@ public final class Settings { */ public static final void setLocationProviderEnabledForUser(ContentResolver cr, String provider, boolean enabled, int userId) { - // to ensure thread safety, we write the provider name with a '+' or '-' - // and let the SettingsProvider handle it rather than reading and modifying - // the list of enabled providers. - if (enabled) { - provider = "+" + provider; - } else { - provider = "-" + provider; + synchronized (mLocationSettingsLock) { + // to ensure thread safety, we write the provider name with a '+' or '-' + // and let the SettingsProvider handle it rather than reading and modifying + // the list of enabled providers. + if (enabled) { + provider = "+" + provider; + } else { + provider = "-" + provider; + } + putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, + userId); } - putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, - userId); } } @@ -5624,6 +5679,12 @@ public final class Settings { public static final String SELINUX_STATUS = "selinux_status"; /** + * Developer setting to force RTL layout. + * @hide + */ + public static final String DEVELOPMENT_FORCE_RTL = "debug.force_rtl"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index e2035c2..596ca8c 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -19,6 +19,8 @@ package android.text; import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import android.os.SystemProperties; +import android.provider.Settings; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; import android.text.style.BackgroundColorSpan; @@ -1743,8 +1745,10 @@ public class TextUtils { return View.LAYOUT_DIRECTION_RTL; } } - - return View.LAYOUT_DIRECTION_LTR; + // If forcing into RTL layout mode, return RTL as default, else LTR + return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false) + ? View.LAYOUT_DIRECTION_RTL + : View.LAYOUT_DIRECTION_LTR; } /** diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 6b530ef..dc31e0b 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -59,13 +59,14 @@ public class SurfaceControl { private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId); private static native IBinder nativeCreateDisplay(String name, boolean secure); + private static native void nativeDestroyDisplay(IBinder displayToken); private static native void nativeSetDisplaySurface( IBinder displayToken, int nativeSurfaceObject); private static native void nativeSetDisplayLayerStack( IBinder displayToken, int layerStack); private static native void nativeSetDisplayProjection( IBinder displayToken, int orientation, - int l, int t, int r, int b, + int l, int t, int r, int b, int L, int T, int R, int B); private static native boolean nativeGetDisplayInfo( IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo); @@ -103,7 +104,7 @@ public class SurfaceControl { * measures will be taken to disallow the surface's content to be copied * from another process. In particular, screenshots and VNC servers will * be disabled, but other measures can take place, for instance the - * surface might not be hardware accelerated. + * surface might not be hardware accelerated. * */ public static final int SECURE = 0x00000080; @@ -247,10 +248,10 @@ public class SurfaceControl { throw new OutOfResourcesException( "Couldn't allocate SurfaceControl native object"); } - + mCloseGuard.open("release"); } - + @Override protected void finalize() throws Throwable { try { @@ -300,7 +301,7 @@ public class SurfaceControl { if (mNativeObject == 0) throw new NullPointerException( "mNativeObject is null. Have you called release() already?"); } - + /* * set surface parameters. * needs to be inside open/closeTransaction block @@ -369,7 +370,7 @@ public class SurfaceControl { public void setWindowCrop(Rect crop) { checkNotReleased(); if (crop != null) { - nativeSetWindowCrop(mNativeObject, + nativeSetWindowCrop(mNativeObject, crop.left, crop.top, crop.right, crop.bottom); } else { nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0); @@ -397,19 +398,19 @@ public class SurfaceControl { public float xDpi; public float yDpi; public boolean secure; - + public PhysicalDisplayInfo() { } - + public PhysicalDisplayInfo(PhysicalDisplayInfo other) { copyFrom(other); } - + @Override public boolean equals(Object o) { return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o); } - + public boolean equals(PhysicalDisplayInfo other) { return other != null && width == other.width @@ -420,12 +421,12 @@ public class SurfaceControl { && yDpi == other.yDpi && secure == other.secure; } - + @Override public int hashCode() { return 0; // don't care } - + public void copyFrom(PhysicalDisplayInfo other) { width = other.width; height = other.height; @@ -435,7 +436,7 @@ public class SurfaceControl { yDpi = other.yDpi; secure = other.secure; } - + // For debugging purposes @Override public String toString() { @@ -481,7 +482,7 @@ public class SurfaceControl { throw new IllegalArgumentException("displayRect must not be null"); } nativeSetDisplayProjection(displayToken, orientation, - layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, + layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, displayRect.left, displayRect.top, displayRect.right, displayRect.bottom); } @@ -513,6 +514,13 @@ public class SurfaceControl { return nativeCreateDisplay(name, secure); } + public static void destroyDisplay(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + nativeDestroyDisplay(displayToken); + } + public static IBinder getBuiltInDisplay(int builtInDisplayId) { return nativeGetBuiltInDisplay(builtInDisplayId); } @@ -608,7 +616,7 @@ public class SurfaceControl { SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); return nativeScreenshot(displayToken, width, height, 0, 0, true); } - + private static void screenshot(IBinder display, Surface consumer, int width, int height, int minLayer, int maxLayer, boolean allLayers) { if (display == null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 20938f5..3dff1b0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12062,7 +12062,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Resolve padding depending on layout direction. + * Resolves padding depending on layout direction, if applicable, and + * recomputes internal padding values to adjust for scroll bars. * * @hide */ @@ -12102,11 +12103,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; - internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, - mUserPaddingBottom); onRtlPropertiesChanged(resolvedLayoutDirection); } + internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); + mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; } @@ -14659,13 +14660,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ protected void resolveDrawables() { - if (canResolveLayoutDirection()) { - if (mBackground != null) { - mBackground.setLayoutDirection(getLayoutDirection()); - } - mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; - onResolveDrawables(getLayoutDirection()); + // Drawables resolution may need to happen before resolving the layout direction (which is + // done only during the measure() call). + // If the layout direction is not resolved yet, we cannot resolve the Drawables except in + // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. + // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or + // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout + // direction to be resolved as its resolved value will be the same as its raw value. + if (!isLayoutDirectionResolved() && + getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { + return; + } + + final int layoutDirection = isLayoutDirectionResolved() ? + getLayoutDirection() : getRawLayoutDirection(); + + if (mBackground != null) { + mBackground.setLayoutDirection(layoutDirection); } + mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; + onResolveDrawables(layoutDirection); } /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3f391ad..0ed846b 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1243,6 +1243,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mFastScroller = new FastScroller(this); mFastScroller.setEnabled(true); } + + recomputePadding(); + + if (mFastScroller != null) { + mFastScroller.updateLayout(); + } } /** @@ -1303,7 +1309,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public int getVerticalScrollbarWidth() { - if (isFastScrollAlwaysVisible() && mFastScroller != null) { + if (mFastScroller != null && mFastScroller.isEnabled()) { return Math.max(super.getVerticalScrollbarWidth(), mFastScroller.getWidth()); } return super.getVerticalScrollbarWidth(); @@ -1327,6 +1333,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } + @Override + public void setScrollBarStyle(int style) { + super.setScrollBarStyle(style); + if (mFastScroller != null) { + mFastScroller.setScrollBarStyle(style); + } + } + /** * If fast scroll is enabled, then don't draw the vertical scrollbar. * @hide @@ -2787,7 +2801,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public void onRtlPropertiesChanged(int layoutDirection) { super.onRtlPropertiesChanged(layoutDirection); - if (mFastScroller != null) { mFastScroller.setScrollbarPosition(getVerticalScrollbarPosition()); } diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 393720f..c48955f 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -131,6 +131,9 @@ class FastScroller { /** Whether there is a track image to display. */ private final boolean mHasTrackImage; + /** Total width of decorations. */ + private final int mWidth; + /** Set containing decoration transition animations. */ private AnimatorSet mDecorAnimation; @@ -155,6 +158,9 @@ class FastScroller { /** The index of the current section. */ private int mCurrentSection = -1; + /** The current scrollbar position. */ + private int mScrollbarPosition = -1; + /** Whether the list is long enough to need a fast scroller. */ private boolean mLongList; @@ -194,6 +200,9 @@ class FastScroller { */ private int mOverlayPosition; + /** Current scrollbar style, including inset and overlay properties. */ + private int mScrollBarStyle; + /** Whether to precisely match the thumb position to the list. */ private boolean mMatchDragPosition; @@ -245,34 +254,44 @@ class FastScroller { final Resources res = context.getResources(); final TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS); - mTrackImage = new ImageView(context); + final ImageView trackImage = new ImageView(context); + mTrackImage = trackImage; + + int width = 0; // Add track to overlay if it has an image. - final int trackResId = ta.getResourceId(TRACK_DRAWABLE, 0); - if (trackResId != 0) { + final Drawable trackDrawable = ta.getDrawable(TRACK_DRAWABLE); + if (trackDrawable != null) { mHasTrackImage = true; - mTrackImage.setBackgroundResource(trackResId); - mOverlay.add(mTrackImage); + trackImage.setBackground(trackDrawable); + mOverlay.add(trackImage); + width = Math.max(width, trackDrawable.getIntrinsicWidth()); } else { mHasTrackImage = false; } - mThumbImage = new ImageView(context); + final ImageView thumbImage = new ImageView(context); + mThumbImage = thumbImage; // Add thumb to overlay if it has an image. final Drawable thumbDrawable = ta.getDrawable(THUMB_DRAWABLE); if (thumbDrawable != null) { - mThumbImage.setImageDrawable(thumbDrawable); - mOverlay.add(mThumbImage); + thumbImage.setImageDrawable(thumbDrawable); + mOverlay.add(thumbImage); + width = Math.max(width, thumbDrawable.getIntrinsicWidth()); } // If necessary, apply minimum thumb width and height. if (thumbDrawable.getIntrinsicWidth() <= 0 || thumbDrawable.getIntrinsicHeight() <= 0) { - mThumbImage.setMinimumWidth(res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width)); - mThumbImage.setMinimumHeight( + final int minWidth = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width); + thumbImage.setMinimumWidth(minWidth); + thumbImage.setMinimumHeight( res.getDimensionPixelSize(R.dimen.fastscroll_thumb_height)); + width = Math.max(width, minWidth); } + mWidth = width; + final int previewSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size); mPreviewImage = new ImageView(context); mPreviewImage.setMinimumWidth(previewSize); @@ -297,10 +316,11 @@ class FastScroller { mOverlayPosition = ta.getInt(OVERLAY_POSITION, OVERLAY_FLOATING); ta.recycle(); + mScrollBarStyle = listView.getScrollBarStyle(); mScrollCompleted = true; mState = STATE_VISIBLE; - mMatchDragPosition = - context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB; + mMatchDragPosition = context.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.HONEYCOMB; getSectionsFromIndexer(); refreshDrawablePressedState(); @@ -362,6 +382,14 @@ class FastScroller { return mAlwaysShow; } + public void setScrollBarStyle(int style) { + if (mScrollBarStyle != style) { + mScrollBarStyle = style; + + updateLayout(); + } + } + /** * Immediately transitions the fast scroller decorations to a hidden state. */ @@ -375,25 +403,29 @@ class FastScroller { View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; } - mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; + if (mScrollbarPosition != position) { + mScrollbarPosition = position; + mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; - final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; - mPreviewImage.setBackgroundResource(previewResId); + final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; + mPreviewImage.setBackgroundResource(previewResId); - // Add extra padding for text. - final Drawable background = mPreviewImage.getBackground(); - if (background != null) { - final Rect padding = mTempBounds; - background.getPadding(padding); - padding.offset(mPreviewPadding, mPreviewPadding); - mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); - } + // Add extra padding for text. + final Drawable background = mPreviewImage.getBackground(); + if (background != null) { + final Rect padding = mTempBounds; + background.getPadding(padding); + padding.offset(mPreviewPadding, mPreviewPadding); + mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); + } - updateLayout(); + // Requires re-layout. + updateLayout(); + } } public int getWidth() { - return mThumbImage.getWidth(); + return mWidth; } public void onSizeChanged(int w, int h, int oldw, int oldh) { @@ -437,7 +469,7 @@ class FastScroller { /** * Measures and layouts the scrollbar and decorations. */ - private void updateLayout() { + public void updateLayout() { // Prevent re-entry when RTL properties change as a side-effect of // resolving padding. if (mUpdatingLayout) { @@ -594,21 +626,36 @@ class FastScroller { out.set(left, top, right, bottom); } + /** + * Updates the container rectangle used for layout. + */ private void updateContainerRect() { final AbsListView list = mList; + list.resolvePadding(); + final Rect container = mContainerRect; container.left = 0; container.top = 0; container.right = list.getWidth(); container.bottom = list.getHeight(); - final int scrollbarStyle = list.getScrollBarStyle(); + final int scrollbarStyle = mScrollBarStyle; if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) { container.left += list.getPaddingLeft(); container.top += list.getPaddingTop(); container.right -= list.getPaddingRight(); container.bottom -= list.getPaddingBottom(); + + // In inset mode, we need to adjust for padded scrollbar width. + if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) { + final int width = getWidth(); + if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) { + container.right += width; + } else { + container.left -= width; + } + } } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3181164..9c21f0d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1378,6 +1378,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0; } + resetResolvedDrawables(); + resolveDrawables(); } } diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 3a2b647..91c47d1 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -18,91 +18,96 @@ package com.android.internal.app; import android.app.Activity; import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.text.method.AllCapsTransformationMethod; +import android.text.method.TransformationMethod; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; public class PlatLogoActivity extends Activity { - Toast mToast; - ImageView mContent; + FrameLayout mContent; int mCount; final Handler mHandler = new Handler(); - private View makeView() { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); - LinearLayout view = new LinearLayout(this); - view.setOrientation(LinearLayout.VERTICAL); - view.setLayoutParams( - new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT - )); - final int p = (int)(8 * metrics.density); - view.setPadding(p, p, p, p); - + Typeface bold = Typeface.create("sans-serif", Typeface.BOLD); Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL); - Typeface normal = Typeface.create("sans-serif", Typeface.BOLD); - final float size = 14 * metrics.density; - final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER_HORIZONTAL; - lp.bottomMargin = (int) (-4*metrics.density); + mContent = new FrameLayout(this); + + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER; - TextView tv = new TextView(this); + final ImageView logo = new ImageView(this); + logo.setImageResource(com.android.internal.R.drawable.platlogo); + logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + logo.setVisibility(View.INVISIBLE); + + final TextView letter = new TextView(this); + + letter.setTypeface(bold); + letter.setTextSize(300); + letter.setTextColor(0xFFFFFFFF); + letter.setGravity(Gravity.CENTER); + letter.setShadowLayer(12*metrics.density, 0, 0, 0xC085F985); + letter.setText(String.valueOf(Build.VERSION.RELEASE).substring(0, 1)); + + final int p = (int)(4 * metrics.density); + + final TextView tv = new TextView(this); if (light != null) tv.setTypeface(light); - tv.setTextSize(1.25f*size); + tv.setTextSize(30); + tv.setPadding(p, p, p, p); tv.setTextColor(0xFFFFFFFF); - tv.setShadowLayer(4*metrics.density, 0, 2*metrics.density, 0x66000000); + tv.setGravity(Gravity.CENTER); + tv.setShadowLayer(4 * metrics.density, 0, 2 * metrics.density, 0x66000000); + tv.setTransformationMethod(new AllCapsTransformationMethod(this)); tv.setText("Android " + Build.VERSION.RELEASE); - view.addView(tv, lp); - - tv = new TextView(this); - if (normal != null) tv.setTypeface(normal); - tv.setTextSize(size); - tv.setTextColor(0xFFFFFFFF); - tv.setShadowLayer(4*metrics.density, 0, 2*metrics.density, 0x66000000); - tv.setText("JELLY BEAN"); - view.addView(tv, lp); + tv.setVisibility(View.INVISIBLE); - return view; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + mContent.addView(letter, lp); + mContent.addView(logo, lp); - mToast = Toast.makeText(this, "", Toast.LENGTH_LONG); - mToast.setView(makeView()); + final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp); + lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + lp2.bottomMargin = 10*p; - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(metrics); - - mContent = new ImageView(this); - mContent.setImageResource(com.android.internal.R.drawable.platlogo_alt); - mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - final int p = (int)(32 * metrics.density); - mContent.setPadding(p, p, p, p); + mContent.addView(tv, lp2); mContent.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mToast.show(); - mContent.setImageResource(com.android.internal.R.drawable.platlogo); + if (logo.getVisibility() != View.VISIBLE) { + letter.animate().alpha(0.25f).scaleY(0.75f).scaleX(0.75f).setDuration(2000) + .start(); + logo.setAlpha(0f); + logo.setVisibility(View.VISIBLE); + logo.animate().alpha(1f).setDuration(1000).setStartDelay(500).start(); + tv.setAlpha(0f); + tv.setVisibility(View.VISIBLE); + tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start(); + } } }); @@ -115,9 +120,8 @@ public class PlatLogoActivity extends Activity { | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) .addCategory("com.android.internal.category.PLATLOGO")); - //.setClassName("com.android.systemui","com.android.systemui.BeanBag")); } catch (ActivityNotFoundException ex) { - android.util.Log.e("PlatLogoActivity", "Couldn't find a bag of beans."); + android.util.Log.e("PlatLogoActivity", "Couldn't find a piece of pie."); } finish(); return true; diff --git a/services/java/com/android/server/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java index 20c97ba..6ff0304 100644 --- a/services/java/com/android/server/ProcessMap.java +++ b/core/java/com/android/internal/app/ProcessMap.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.internal.app; import android.util.ArrayMap; import android.util.SparseArray; diff --git a/services/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index 5e9b6a1..7eadbb5 100644 --- a/services/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -29,9 +29,10 @@ import android.util.SparseArray; import android.util.TimeUtils; import android.webkit.WebViewFactory; import com.android.internal.util.ArrayUtils; -import com.android.server.ProcessMap; import dalvik.system.VMRuntime; +import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -39,10 +40,12 @@ import java.util.Collections; import java.util.Comparator; import java.util.Objects; -final public class ProcessStats implements Parcelable { +public final class ProcessStats implements Parcelable { static final String TAG = "ProcessStats"; static final boolean DEBUG = false; - + + public static final String SERVICE_NAME = "procstats"; + public static final int STATE_NOTHING = -1; public static final int STATE_PERSISTENT = 0; public static final int STATE_TOP = 1; @@ -84,13 +87,20 @@ final public class ProcessStats implements Parcelable { public static final int FLAG_SHUTDOWN = 1<<1; public static final int FLAG_SYSPROPS = 1<<2; - static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, ADJ_MEM_FACTOR_MODERATE, - ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL }; - static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON }; - static final int[] NON_CACHED_PROC_STATES = new int[] { STATE_PERSISTENT, - STATE_TOP, STATE_IMPORTANT_FOREGROUND, + public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, + ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL }; + + public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON }; + + public static final int[] NON_CACHED_PROC_STATES = new int[] { + STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT, - STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HOME + STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER + }; + + public static final int[] BACKGROUND_PROC_STATES = new int[] { + STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, + STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER }; // Map from process states to the states we track. @@ -204,6 +214,80 @@ final public class ProcessStats implements Parcelable { readFromParcel(in); } + public void add(ProcessStats other) { + ArrayMap<String, SparseArray<PackageState>> pkgMap = other.mPackages.getMap(); + for (int ip=0; ip<pkgMap.size(); ip++) { + String pkgName = pkgMap.keyAt(ip); + SparseArray<PackageState> uids = pkgMap.valueAt(ip); + for (int iu=0; iu<uids.size(); iu++) { + int uid = uids.keyAt(iu); + PackageState otherState = uids.valueAt(iu); + final int NPROCS = otherState.mProcesses.size(); + final int NSRVS = otherState.mServices.size(); + for (int iproc=0; iproc<NPROCS; iproc++) { + ProcessState otherProc = otherState.mProcesses.valueAt(iproc); + if (otherProc.mCommonProcess != otherProc) { + if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid + + " proc " + otherProc.mName); + ProcessState thisProc = getProcessStateLocked(pkgName, uid, + otherProc.mName); + if (thisProc.mCommonProcess == thisProc) { + if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting"); + thisProc.mMultiPackage = true; + long now = SystemClock.uptimeMillis(); + final PackageState pkgState = getPackageStateLocked(pkgName, uid); + thisProc = thisProc.clone(thisProc.mPackage, now); + pkgState.mProcesses.put(thisProc.mName, thisProc); + } + thisProc.add(otherProc); + } + } + for (int isvc=0; isvc<NSRVS; isvc++) { + ServiceState otherSvc = otherState.mServices.valueAt(isvc); + if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid + + " service " + otherSvc.mName); + ServiceState thisSvc = getServiceStateLocked(pkgName, uid, + null, otherSvc.mName); + thisSvc.add(otherSvc); + } + } + } + + ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap(); + for (int ip=0; ip<procMap.size(); ip++) { + SparseArray<ProcessState> uids = procMap.valueAt(ip); + for (int iu=0; iu<uids.size(); iu++) { + int uid = uids.keyAt(iu); + ProcessState otherProc = uids.valueAt(iu); + ProcessState thisProc = mProcesses.get(otherProc.mName, uid); + if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + otherProc.mName); + if (thisProc == null) { + if (DEBUG) Slog.d(TAG, "Creating new process!"); + thisProc = new ProcessState(this, otherProc.mPackage, uid, otherProc.mName); + mProcesses.put(otherProc.mName, uid, thisProc); + PackageState thisState = getPackageStateLocked(otherProc.mPackage, uid); + if (!thisState.mProcesses.containsKey(otherProc.mName)) { + thisState.mProcesses.put(otherProc.mName, thisProc); + } + } + thisProc.add(otherProc); + } + } + + for (int i=0; i<ADJ_COUNT; i++) { + if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by " + + other.mMemFactorDurations[i] + " from " + + mMemFactorDurations[i]); + mMemFactorDurations[i] += other.mMemFactorDurations[i]; + } + + if (other.mTimePeriodStartClock < mTimePeriodStartClock) { + mTimePeriodStartClock = other.mTimePeriodStartClock; + mTimePeriodStartClockStr = other.mTimePeriodStartClockStr; + } + mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime; + } + public static final Parcelable.Creator<ProcessStats> CREATOR = new Parcelable.Creator<ProcessStats>() { public ProcessStats createFromParcel(Parcel in) { @@ -215,7 +299,7 @@ final public class ProcessStats implements Parcelable { } }; - static private void printScreenLabel(PrintWriter pw, int offset) { + private static void printScreenLabel(PrintWriter pw, int offset) { switch (offset) { case ADJ_NOTHING: pw.print(" "); @@ -232,7 +316,7 @@ final public class ProcessStats implements Parcelable { } } - static public void printScreenLabelCsv(PrintWriter pw, int offset) { + public static void printScreenLabelCsv(PrintWriter pw, int offset) { switch (offset) { case ADJ_NOTHING: break; @@ -248,7 +332,7 @@ final public class ProcessStats implements Parcelable { } } - static private void printMemLabel(PrintWriter pw, int offset) { + private static void printMemLabel(PrintWriter pw, int offset) { switch (offset) { case ADJ_NOTHING: pw.print(" "); @@ -271,7 +355,7 @@ final public class ProcessStats implements Parcelable { } } - static public void printMemLabelCsv(PrintWriter pw, int offset) { + public static void printMemLabelCsv(PrintWriter pw, int offset) { if (offset >= ADJ_MEM_FACTOR_NORMAL) { if (offset <= ADJ_MEM_FACTOR_CRITICAL) { pw.print(ADJ_MEM_NAMES_CSV[offset]); @@ -281,7 +365,7 @@ final public class ProcessStats implements Parcelable { } } - static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations, + public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now) { long totalTime = 0; int printedScreen = -1; @@ -361,7 +445,7 @@ final public class ProcessStats implements Parcelable { if (type != serviceType) { continue; } - long time = svc.mProcessStats.getLong(off, 0); + long time = svc.mStats.getLong(off, 0); if (curState == memFactor) { didCurState = true; time += now - curStartTime; @@ -374,7 +458,7 @@ final public class ProcessStats implements Parcelable { pw.println(); } - static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) { + public static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) { data.totalTime = 0; data.numPss = data.minPss = data.avgPss = data.maxPss = data.minUss = data.avgUss = data.maxUss = 0; @@ -815,7 +899,7 @@ final public class ProcessStats implements Parcelable { for (int i=0; i<proc.mDurationsTableSize; i++) { int off = proc.mDurationsTable[i]; int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; - long time = proc.mProcessStats.getLong(off, 0); + long time = proc.mStats.getLong(off, 0); if (proc.mCurState == type) { didCurState = true; time += now - proc.mStartTime; @@ -831,13 +915,13 @@ final public class ProcessStats implements Parcelable { for (int i=0; i<proc.mPssTableSize; i++) { int off = proc.mPssTable[i]; int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; - long count = proc.mProcessStats.getLong(off, PSS_SAMPLE_COUNT); - long min = proc.mProcessStats.getLong(off, PSS_MINIMUM); - long avg = proc.mProcessStats.getLong(off, PSS_AVERAGE); - long max = proc.mProcessStats.getLong(off, PSS_MAXIMUM); - long umin = proc.mProcessStats.getLong(off, PSS_USS_MINIMUM); - long uavg = proc.mProcessStats.getLong(off, PSS_USS_AVERAGE); - long umax = proc.mProcessStats.getLong(off, PSS_USS_MAXIMUM); + long count = proc.mStats.getLong(off, PSS_SAMPLE_COUNT); + long min = proc.mStats.getLong(off, PSS_MINIMUM); + long avg = proc.mStats.getLong(off, PSS_AVERAGE); + long max = proc.mStats.getLong(off, PSS_MAXIMUM); + long umin = proc.mStats.getLong(off, PSS_USS_MINIMUM); + long uavg = proc.mStats.getLong(off, PSS_USS_AVERAGE); + long umax = proc.mStats.getLong(off, PSS_USS_MAXIMUM); pw.print(','); printProcStateTag(pw, type); pw.print(':'); @@ -979,6 +1063,37 @@ final public class ProcessStats implements Parcelable { out.writeInt(PSS_COUNT); out.writeInt(LONGS_SIZE); + // First commit all running times. + ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); + final int NPROC = procMap.size(); + for (int ip=0; ip<NPROC; ip++) { + SparseArray<ProcessState> uids = procMap.valueAt(ip); + final int NUID = uids.size(); + for (int iu=0; iu<NUID; iu++) { + uids.valueAt(iu).commitStateTime(now); + } + } + ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap(); + final int NPKG = pkgMap.size(); + for (int ip=0; ip<NPKG; ip++) { + SparseArray<PackageState> uids = pkgMap.valueAt(ip); + final int NUID = uids.size(); + for (int iu=0; iu<NUID; iu++) { + PackageState pkgState = uids.valueAt(iu); + final int NPROCS = pkgState.mProcesses.size(); + for (int iproc=0; iproc<NPROCS; iproc++) { + ProcessState proc = pkgState.mProcesses.valueAt(iproc); + if (proc.mCommonProcess != proc) { + proc.commitStateTime(now); + } + } + final int NSRVS = pkgState.mServices.size(); + for (int isvc=0; isvc<NSRVS; isvc++) { + pkgState.mServices.valueAt(isvc).commitStateTime(now); + } + } + } + out.writeLong(mTimePeriodStartClock); out.writeLong(mTimePeriodStartRealtime); out.writeLong(mTimePeriodEndRealtime); @@ -991,7 +1106,7 @@ final public class ProcessStats implements Parcelable { for (int i=0; i<(mLongs.size()-1); i++) { out.writeLongArray(mLongs.get(i)); } - long[] lastLongs = mLongs.get(mLongs.size()-1); + long[] lastLongs = mLongs.get(mLongs.size() - 1); for (int i=0; i<mNextLong; i++) { out.writeLong(lastLongs[i]); if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]); @@ -1003,8 +1118,6 @@ final public class ProcessStats implements Parcelable { } out.writeLongArray(mMemFactorDurations); - ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); - final int NPROC = procMap.size(); out.writeInt(NPROC); for (int ip=0; ip<NPROC; ip++) { out.writeString(procMap.keyAt(ip)); @@ -1018,8 +1131,6 @@ final public class ProcessStats implements Parcelable { proc.writeToParcel(out, now); } } - ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap(); - final int NPKG = pkgMap.size(); out.writeInt(NPKG); for (int ip=0; ip<NPKG; ip++) { out.writeString(pkgMap.keyAt(ip)); @@ -1063,6 +1174,43 @@ final public class ProcessStats implements Parcelable { return true; } + static byte[] readFully(InputStream stream) throws IOException { + int pos = 0; + int avail = stream.available(); + byte[] data = new byte[avail]; + while (true) { + int amt = stream.read(data, pos, data.length-pos); + //Log.i("foo", "Read " + amt + " bytes at " + pos + // + " of avail " + data.length); + if (amt <= 0) { + //Log.i("foo", "**** FINISHED READING: pos=" + pos + // + " len=" + data.length); + return data; + } + pos += amt; + avail = stream.available(); + if (avail > data.length-pos) { + byte[] newData = new byte[pos+avail]; + System.arraycopy(data, 0, newData, 0, pos); + data = newData; + } + } + } + + public void read(InputStream stream) { + try { + byte[] raw = readFully(stream); + Parcel in = Parcel.obtain(); + in.unmarshall(raw, 0, raw.length); + in.setDataPosition(0); + stream.close(); + + readFromParcel(in); + } catch (IOException e) { + mReadError = "caught exception: " + e; + } + } + public void readFromParcel(Parcel in) { final boolean hadData = mPackages.getMap().size() > 0 || mProcesses.getMap().size() > 0; @@ -1254,7 +1402,7 @@ final public class ProcessStats implements Parcelable { } ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null; if (serv == null) { - serv = new ServiceState(this, pkgName, null); + serv = new ServiceState(this, pkgName, serviceName, null); } if (!serv.readFromParcel(in)) { return; @@ -1402,6 +1550,21 @@ final public class ProcessStats implements Parcelable { return ps; } + public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid, + String processName, String className) { + final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid); + ProcessStats.ServiceState ss = as.mServices.get(className); + if (ss != null) { + ss.makeActive(); + return ss; + } + final ProcessStats.ProcessState ps = processName != null + ? getProcessStateLocked(packageName, uid, processName) : null; + ss = new ProcessStats.ServiceState(this, packageName, className, ps); + as.mServices.put(className, ss); + return ss; + } + public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) { long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, mStartTime, now); @@ -1530,11 +1693,8 @@ final public class ProcessStats implements Parcelable { long time = service.getDuration(serviceType, curState, curStartTime, state, now); String running = ""; - if (curState == state) { - time += now - curStartTime; - if (pw != null) { - running = " (running)"; - } + if (curState == state && pw != null) { + running = " (running)"; } if (time != 0) { if (pw != null) { @@ -1824,11 +1984,11 @@ final public class ProcessStats implements Parcelable { } public static final class ProcessState { - final ProcessStats mProcessStats; - final ProcessState mCommonProcess; - final String mPackage; - final int mUid; - final String mName; + public final ProcessStats mStats; + public final ProcessState mCommonProcess; + public final String mPackage; + public final int mUid; + public final String mName; int[] mDurationsTable; int mDurationsTableSize; @@ -1849,14 +2009,14 @@ final public class ProcessStats implements Parcelable { boolean mMultiPackage; - long mTmpTotalTime; + public long mTmpTotalTime; /** * Create a new top-level process state, for the initial case where there is only * a single package running in a process. The initial state is not running. */ public ProcessState(ProcessStats processStats, String pkg, int uid, String name) { - mProcessStats = processStats; + mStats = processStats; mCommonProcess = this; mPackage = pkg; mUid = uid; @@ -1870,7 +2030,7 @@ final public class ProcessStats implements Parcelable { */ public ProcessState(ProcessState commonProcess, String pkg, int uid, String name, long now) { - mProcessStats = commonProcess.mProcessStats; + mStats = commonProcess.mStats; mCommonProcess = commonProcess; mPackage = pkg; mUid = uid; @@ -1882,32 +2042,32 @@ final public class ProcessStats implements Parcelable { ProcessState clone(String pkg, long now) { ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now); if (mDurationsTable != null) { - mProcessStats.mAddLongTable = new int[mDurationsTable.length]; - mProcessStats.mAddLongTableSize = 0; + mStats.mAddLongTable = new int[mDurationsTable.length]; + mStats.mAddLongTableSize = 0; for (int i=0; i<mDurationsTableSize; i++) { int origEnt = mDurationsTable[i]; int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; - int newOff = mProcessStats.addLongData(i, type, 1); - mProcessStats.mAddLongTable[i] = newOff | type; - mProcessStats.setLong(newOff, 0, mProcessStats.getLong(origEnt, 0)); + int newOff = mStats.addLongData(i, type, 1); + mStats.mAddLongTable[i] = newOff | type; + mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0)); } - pnew.mDurationsTable = mProcessStats.mAddLongTable; - pnew.mDurationsTableSize = mProcessStats.mAddLongTableSize; + pnew.mDurationsTable = mStats.mAddLongTable; + pnew.mDurationsTableSize = mStats.mAddLongTableSize; } if (mPssTable != null) { - mProcessStats.mAddLongTable = new int[mPssTable.length]; - mProcessStats.mAddLongTableSize = 0; + mStats.mAddLongTable = new int[mPssTable.length]; + mStats.mAddLongTableSize = 0; for (int i=0; i<mPssTableSize; i++) { int origEnt = mPssTable[i]; int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; - int newOff = mProcessStats.addLongData(i, type, PSS_COUNT); - mProcessStats.mAddLongTable[i] = newOff | type; + int newOff = mStats.addLongData(i, type, PSS_COUNT); + mStats.mAddLongTable[i] = newOff | type; for (int j=0; j<PSS_COUNT; j++) { - mProcessStats.setLong(newOff, j, mProcessStats.getLong(origEnt, j)); + mStats.setLong(newOff, j, mStats.getLong(origEnt, j)); } } - pnew.mPssTable = mProcessStats.mAddLongTable; - pnew.mPssTableSize = mProcessStats.mAddLongTableSize; + pnew.mPssTable = mStats.mAddLongTable; + pnew.mPssTableSize = mStats.mAddLongTableSize; } pnew.mNumExcessiveWake = mNumExcessiveWake; pnew.mNumExcessiveCpu = mNumExcessiveCpu; @@ -1915,6 +2075,29 @@ final public class ProcessStats implements Parcelable { return pnew; } + void add(ProcessState other) { + for (int i=0; i<other.mDurationsTableSize; i++) { + int ent = other.mDurationsTable[i]; + int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; + if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration " + + other.mStats.getLong(ent, 0)); + addDuration(state, other.mStats.getLong(ent, 0)); + } + for (int i=0; i<other.mPssTableSize; i++) { + int ent = other.mPssTable[i]; + int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; + addPss(state, (int) other.mStats.getLong(ent, PSS_SAMPLE_COUNT), + other.mStats.getLong(ent, PSS_MINIMUM), + other.mStats.getLong(ent, PSS_AVERAGE), + other.mStats.getLong(ent, PSS_MAXIMUM), + other.mStats.getLong(ent, PSS_USS_MINIMUM), + other.mStats.getLong(ent, PSS_USS_AVERAGE), + other.mStats.getLong(ent, PSS_USS_MAXIMUM)); + } + mNumExcessiveWake += other.mNumExcessiveWake; + mNumExcessiveCpu += other.mNumExcessiveCpu; + } + void resetSafely(long now) { mDurationsTable = null; mDurationsTableSize = 0; @@ -1928,7 +2111,6 @@ final public class ProcessStats implements Parcelable { } void writeToParcel(Parcel out, long now) { - commitStateTime(now); out.writeInt(mMultiPackage ? 1 : 0); out.writeInt(mDurationsTableSize); for (int i=0; i<mDurationsTableSize; i++) { @@ -1952,13 +2134,13 @@ final public class ProcessStats implements Parcelable { mMultiPackage = multiPackage; } if (DEBUG) Slog.d(TAG, "Reading durations table..."); - mDurationsTable = mProcessStats.readTableFromParcel(in, mName, "durations"); + mDurationsTable = mStats.readTableFromParcel(in, mName, "durations"); if (mDurationsTable == BAD_TABLE) { return false; } mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0; if (DEBUG) Slog.d(TAG, "Reading pss table..."); - mPssTable = mProcessStats.readTableFromParcel(in, mName, "pss"); + mPssTable = mStats.readTableFromParcel(in, mName, "pss"); if (mPssTable == BAD_TABLE) { return false; } @@ -2012,24 +2194,30 @@ final public class ProcessStats implements Parcelable { if (mCurState != STATE_NOTHING) { long dur = now - mStartTime; if (dur > 0) { - int idx = binarySearch(mDurationsTable, mDurationsTableSize, mCurState); - int off; - if (idx >= 0) { - off = mDurationsTable[idx]; - } else { - mProcessStats.mAddLongTable = mDurationsTable; - mProcessStats.mAddLongTableSize = mDurationsTableSize; - off = mProcessStats.addLongData(~idx, mCurState, 1); - mDurationsTable = mProcessStats.mAddLongTable; - mDurationsTableSize = mProcessStats.mAddLongTableSize; - } - long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK); - longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur; + addDuration(mCurState, dur); } } mStartTime = now; } + void addDuration(int state, long dur) { + int idx = binarySearch(mDurationsTable, mDurationsTableSize, state); + int off; + if (idx >= 0) { + off = mDurationsTable[idx]; + } else { + mStats.mAddLongTable = mDurationsTable; + mStats.mAddLongTableSize = mDurationsTableSize; + off = mStats.addLongData(~idx, state, 1); + mDurationsTable = mStats.mAddLongTable; + mDurationsTableSize = mStats.mAddLongTableSize; + } + long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK); + if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur + + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]); + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur; + } + void incStartedServices(int memFactor, long now) { if (mCommonProcess != this) { mCommonProcess.incStartedServices(memFactor, now); @@ -2063,46 +2251,53 @@ final public class ProcessStats implements Parcelable { mLastPssState = mCurState; mLastPssTime = SystemClock.uptimeMillis(); if (mCurState != STATE_NOTHING) { - int idx = binarySearch(mPssTable, mPssTableSize, mCurState); - int off; - if (idx >= 0) { - off = mPssTable[idx]; - } else { - mProcessStats.mAddLongTable = mPssTable; - mProcessStats.mAddLongTableSize = mPssTableSize; - off = mProcessStats.addLongData(~idx, mCurState, PSS_COUNT); - mPssTable = mProcessStats.mAddLongTable; - mPssTableSize = mProcessStats.mAddLongTableSize; + addPss(mCurState, 1, pss, pss, pss, uss, uss, uss); + } + } + + void addPss(int state, int inCount, long minPss, long avgPss, long maxPss, long minUss, + long avgUss, long maxUss) { + int idx = binarySearch(mPssTable, mPssTableSize, state); + int off; + if (idx >= 0) { + off = mPssTable[idx]; + } else { + mStats.mAddLongTable = mPssTable; + mStats.mAddLongTableSize = mPssTableSize; + off = mStats.addLongData(~idx, state, PSS_COUNT); + mPssTable = mStats.mAddLongTable; + mPssTableSize = mStats.mAddLongTableSize; + } + long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK); + idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK; + long count = longs[idx+PSS_SAMPLE_COUNT]; + if (count == 0) { + longs[idx+PSS_SAMPLE_COUNT] = inCount; + longs[idx+PSS_MINIMUM] = minPss; + longs[idx+PSS_AVERAGE] = avgPss; + longs[idx+PSS_MAXIMUM] = maxPss; + longs[idx+PSS_USS_MINIMUM] = minUss; + longs[idx+PSS_USS_AVERAGE] = avgUss; + longs[idx+PSS_USS_MAXIMUM] = maxUss; + } else { + longs[idx+PSS_SAMPLE_COUNT] = count+inCount; + if (longs[idx+PSS_MINIMUM] > minPss) { + longs[idx+PSS_MINIMUM] = minPss; } - long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK); - idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK; - long count = longs[idx+PSS_SAMPLE_COUNT]; - if (count == 0) { - longs[idx+PSS_SAMPLE_COUNT] = 1; - longs[idx+PSS_MINIMUM] = pss; - longs[idx+PSS_AVERAGE] = pss; - longs[idx+PSS_MAXIMUM] = pss; - longs[idx+PSS_USS_MINIMUM] = uss; - longs[idx+PSS_USS_AVERAGE] = uss; - longs[idx+PSS_USS_MAXIMUM] = uss; - } else { - longs[idx+PSS_SAMPLE_COUNT] = count+1; - if (longs[idx+PSS_MINIMUM] > pss) { - longs[idx+PSS_MINIMUM] = pss; - } - longs[idx+PSS_AVERAGE] = (long)( - ((longs[idx+PSS_AVERAGE]*(double)count)+pss) / (count+1) ); - if (longs[idx+PSS_MAXIMUM] < pss) { - longs[idx+PSS_MAXIMUM] = pss; - } - if (longs[idx+PSS_USS_MINIMUM] > uss) { - longs[idx+PSS_USS_MINIMUM] = uss; - } - longs[idx+PSS_USS_AVERAGE] = (long)( - ((longs[idx+PSS_USS_AVERAGE]*(double)count)+uss) / (count+1) ); - if (longs[idx+PSS_USS_MAXIMUM] < uss) { - longs[idx+PSS_USS_MAXIMUM] = uss; - } + longs[idx+PSS_AVERAGE] = (long)( + ((longs[idx+PSS_AVERAGE]*(double)count)+(avgPss*(double)inCount)) + / (count+inCount) ); + if (longs[idx+PSS_MAXIMUM] < maxPss) { + longs[idx+PSS_MAXIMUM] = maxPss; + } + if (longs[idx+PSS_USS_MINIMUM] > minUss) { + longs[idx+PSS_USS_MINIMUM] = minUss; + } + longs[idx+PSS_USS_AVERAGE] = (long)( + ((longs[idx+PSS_USS_AVERAGE]*(double)count)+(avgUss*(double)inCount)) + / (count+inCount) ); + if (longs[idx+PSS_USS_MAXIMUM] < maxUss) { + longs[idx+PSS_USS_MAXIMUM] = maxUss; } } } @@ -2134,7 +2329,7 @@ final public class ProcessStats implements Parcelable { // The array map is still pointing to a common process state // that is now shared across packages. Update it to point to // the new per-package state. - ProcessState proc = mProcessStats.mPackages.get(pkgName, + ProcessState proc = mStats.mPackages.get(pkgName, mUid).mProcesses.get(mName); if (proc == null) { throw new IllegalStateException("Didn't create per-package process"); @@ -2151,7 +2346,7 @@ final public class ProcessStats implements Parcelable { // The array map is still pointing to a common process state // that is now shared across packages. Update it to point to // the new per-package state. - proc = mProcessStats.mPackages.get(pkgList.keyAt(index), + proc = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid).mProcesses.get(proc.mName); if (proc == null) { throw new IllegalStateException("Didn't create per-package process"); @@ -2163,7 +2358,7 @@ final public class ProcessStats implements Parcelable { long getDuration(int state, long now) { int idx = binarySearch(mDurationsTable, mDurationsTableSize, state); - long time = idx >= 0 ? mProcessStats.getLong(mDurationsTable[idx], 0) : 0; + long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0; if (mCurState == state) { time += now - mStartTime; } @@ -2172,43 +2367,44 @@ final public class ProcessStats implements Parcelable { long getPssSampleCount(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0; } long getPssMinimum(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0; } long getPssAverage(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0; } long getPssMaximum(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0; } long getPssUssMinimum(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0; } long getPssUssAverage(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0; } long getPssUssMaximum(int state) { int idx = binarySearch(mPssTable, mPssTableSize, state); - return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0; + return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0; } } public static final class ServiceState { - final ProcessStats mProcessStats; + final ProcessStats mStats; final String mPackage; + final String mName; ProcessState mProc; int mActive = 1; @@ -2233,9 +2429,10 @@ final public class ProcessStats implements Parcelable { public int mExecState = STATE_NOTHING; long mExecStartTime; - public ServiceState(ProcessStats processStats, String pkg, ProcessState proc) { - mProcessStats = processStats; + public ServiceState(ProcessStats processStats, String pkg, String name, ProcessState proc) { + mStats = processStats; mPackage = pkg; + mName = name; mProc = proc; } @@ -2256,6 +2453,17 @@ final public class ProcessStats implements Parcelable { return mActive > 0; } + void add(ServiceState other) { + for (int i=0; i<other.mDurationsTableSize; i++) { + int ent = other.mDurationsTable[i]; + int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK; + addStateTime(state, other.mStats.getLong(ent, 0)); + } + mStartedCount += other.mStartedCount; + mBoundCount += other.mBoundCount; + mExecCount += other.mExecCount; + } + void resetSafely(long now) { mDurationsTable = null; mDurationsTableSize = 0; @@ -2266,18 +2474,6 @@ final public class ProcessStats implements Parcelable { } void writeToParcel(Parcel out, long now) { - if (mStartedState != STATE_NOTHING) { - addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime); - mStartedStartTime = now; - } - if (mBoundState != STATE_NOTHING) { - addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime); - mBoundStartTime = now; - } - if (mExecState != STATE_NOTHING) { - addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime); - mExecStartTime = now; - } out.writeInt(mDurationsTableSize); for (int i=0; i<mDurationsTableSize; i++) { if (DEBUG) Slog.i(TAG, "Writing service in " + mPackage + " dur #" + i + ": " @@ -2291,7 +2487,7 @@ final public class ProcessStats implements Parcelable { boolean readFromParcel(Parcel in) { if (DEBUG) Slog.d(TAG, "Reading durations table..."); - mDurationsTable = mProcessStats.readTableFromParcel(in, mPackage, "service"); + mDurationsTable = mStats.readTableFromParcel(in, mPackage, "service"); if (mDurationsTable == BAD_TABLE) { return false; } @@ -2302,25 +2498,40 @@ final public class ProcessStats implements Parcelable { return true; } - void addStateTime(int opType, int memFactor, long time) { + void addStateTime(int state, long time) { if (time > 0) { - int state = opType + (memFactor*SERVICE_COUNT); int idx = binarySearch(mDurationsTable, mDurationsTableSize, state); int off; if (idx >= 0) { off = mDurationsTable[idx]; } else { - mProcessStats.mAddLongTable = mDurationsTable; - mProcessStats.mAddLongTableSize = mDurationsTableSize; - off = mProcessStats.addLongData(~idx, state, 1); - mDurationsTable = mProcessStats.mAddLongTable; - mDurationsTableSize = mProcessStats.mAddLongTableSize; + mStats.mAddLongTable = mDurationsTable; + mStats.mAddLongTableSize = mDurationsTableSize; + off = mStats.addLongData(~idx, state, 1); + mDurationsTable = mStats.mAddLongTable; + mDurationsTableSize = mStats.mAddLongTableSize; } - long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK); + long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK); longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += time; } } + void commitStateTime(long now) { + if (mStartedState != STATE_NOTHING) { + addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT), + now - mStartedStartTime); + mStartedStartTime = now; + } + if (mBoundState != STATE_NOTHING) { + addStateTime(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime); + mBoundStartTime = now; + } + if (mExecState != STATE_NOTHING) { + addStateTime(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime); + mExecStartTime = now; + } + } + public void setStarted(boolean started, int memFactor, long now) { if (mActive <= 0) { throw new IllegalStateException("Service " + this + " has mActive=" + mActive); @@ -2328,7 +2539,8 @@ final public class ProcessStats implements Parcelable { int state = started ? memFactor : STATE_NOTHING; if (mStartedState != state) { if (mStartedState != STATE_NOTHING) { - addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime); + addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT), + now - mStartedStartTime); } else if (started) { mStartedCount++; } @@ -2352,7 +2564,8 @@ final public class ProcessStats implements Parcelable { int state = bound ? memFactor : STATE_NOTHING; if (mBoundState != state) { if (mBoundState != STATE_NOTHING) { - addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime); + addStateTime(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), + now - mBoundStartTime); } else if (bound) { mBoundCount++; } @@ -2368,7 +2581,7 @@ final public class ProcessStats implements Parcelable { int state = executing ? memFactor : STATE_NOTHING; if (mExecState != state) { if (mExecState != STATE_NOTHING) { - addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime); + addStateTime(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime); } else if (executing) { mExecCount++; } @@ -2377,25 +2590,11 @@ final public class ProcessStats implements Parcelable { } } - long getStartDuration(int opType, int memFactor, long now) { - switch (opType) { - case SERVICE_STARTED: - return getDuration(opType, mStartedState, mStartedStartTime, memFactor, now); - case SERVICE_BOUND: - return getDuration(opType, mBoundState, mBoundStartTime, memFactor, now); - case SERVICE_EXEC: - return getDuration(opType, mExecState, mExecStartTime, memFactor, now); - default: - throw new IllegalArgumentException("Bad opType: " + opType); - } - } - - private long getDuration(int opType, int curState, long startTime, int memFactor, long now) { int state = opType + (memFactor*SERVICE_COUNT); int idx = binarySearch(mDurationsTable, mDurationsTableSize, state); - long time = idx >= 0 ? mProcessStats.getLong(mDurationsTable[idx], 0) : 0; + long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0; if (curState == memFactor) { time += now - startTime; } @@ -2415,21 +2614,21 @@ final public class ProcessStats implements Parcelable { } } - static final class ProcessDataCollection { + public static final class ProcessDataCollection { final int[] screenStates; final int[] memStates; final int[] procStates; - long totalTime; - long numPss; - long minPss; - long avgPss; - long maxPss; - long minUss; - long avgUss; - long maxUss; + public long totalTime; + public long numPss; + public long minPss; + public long avgPss; + public long maxPss; + public long minUss; + public long avgUss; + public long maxUss; - ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) { + public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) { screenStates = _screenStates; memStates = _memStates; procStates = _procStates; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index ccc0089..04351da 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -499,7 +499,7 @@ public class ZygoteInit { String args[] = { "--setuid=1000", "--setgid=1000", - "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007", + "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--runtime-init", "--nice-name=system_server", diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 3308064..6c4526e 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -35,8 +35,6 @@ #include <utils/Log.h> -#define TIME_DRAWx - static uint32_t get_thread_msec() { #if defined(HAVE_POSIX_CLOCKS) struct timespec tm; @@ -463,20 +461,6 @@ public: canvas->drawPath(*path, *paint); } - static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas, - SkPicture* picture) { - SkASSERT(canvas); - SkASSERT(picture); - -#ifdef TIME_DRAW - SkMSec now = get_thread_msec(); //SkTime::GetMSecs(); -#endif - canvas->drawPicture(*picture); -#ifdef TIME_DRAW - ALOGD("---- picture playback %d ms\n", get_thread_msec() - now); -#endif - } - static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas, SkCanvas* canvas, SkBitmap* bitmap, jfloat left, jfloat top, @@ -1103,7 +1087,6 @@ static JNINativeMethod gCanvasMethods[] = { (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V", (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, - {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}, diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index 2c482ea..bacfdf6 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -18,6 +18,9 @@ #include <stdio.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + #include <gui/GLConsumer.h> #include <gui/Surface.h> diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 7e70c7c..6d23c32 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -141,7 +141,7 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr dns, server, &lease, vendorInfo, domains, mtu); } if (result != 0) { - ALOGD("dhcp_do_request failed"); + ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new"); } env->ReleaseStringUTFChars(ifname, nameStr); diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 08962e2..aa6dbf3 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -33,11 +33,11 @@ namespace android { static jint DBG = false; -static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuflen) +static int doCommand(char *cmd, char *replybuf, int replybuflen) { size_t reply_len = replybuflen - 1; - if (::wifi_command(ifname, cmd, BUF_SIZE, replybuf, &reply_len) != 0) + if (::wifi_command(cmd, replybuf, &reply_len) != 0) return -1; else { // Strip off trailing newline @@ -49,7 +49,7 @@ static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuf } } -static jint doIntCommand(const char *ifname, const char* fmt, ...) +static jint doIntCommand(const char* fmt, ...) { char buf[BUF_SIZE]; va_list args; @@ -60,13 +60,13 @@ static jint doIntCommand(const char *ifname, const char* fmt, ...) return -1; } char reply[BUF_SIZE]; - if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) { + if (doCommand(buf, reply, sizeof(reply)) != 0) { return -1; } return static_cast<jint>(atoi(reply)); } -static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...) +static jboolean doBooleanCommand(const char* expect, const char* fmt, ...) { char buf[BUF_SIZE]; va_list args; @@ -77,14 +77,14 @@ static jboolean doBooleanCommand(const char *ifname, const char* expect, const c return JNI_FALSE; } char reply[BUF_SIZE]; - if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) { + if (doCommand(buf, reply, sizeof(reply)) != 0) { return JNI_FALSE; } return (strcmp(reply, expect) == 0); } // Send a command to the supplicant, and return the reply as a String -static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, ...) { +static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) { char buf[BUF_SIZE]; va_list args; va_start(args, fmt); @@ -94,7 +94,7 @@ static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, return NULL; } char reply[4096]; - if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) { + if (doCommand(buf, reply, sizeof(reply)) != 0) { return NULL; } // TODO: why not just NewStringUTF? @@ -127,23 +127,20 @@ static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0); } -static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface) +static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject) { - ScopedUtfChars ifname(env, jIface); - return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0); + return (jboolean)(::wifi_connect_to_supplicant() == 0); } -static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject, jstring jIface) +static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject) { - ScopedUtfChars ifname(env, jIface); - ::wifi_close_supplicant_connection(ifname.c_str()); + ::wifi_close_supplicant_connection(); } -static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIface) +static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject) { char buf[EVENT_BUF_SIZE]; - ScopedUtfChars ifname(env, jIface); - int nread = ::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf); + int nread = ::wifi_wait_for_event(buf, sizeof buf); if (nread > 0) { return env->NewStringUTF(buf); } else { @@ -151,43 +148,36 @@ static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIfac } } -static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface, - jstring jCommand) +static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jCommand) { - ScopedUtfChars ifname(env, jIface); ScopedUtfChars command(env, jCommand); if (command.c_str() == NULL) { return JNI_FALSE; } if (DBG) ALOGD("doBoolean: %s", command.c_str()); - return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str()); + return doBooleanCommand("OK", "%s", command.c_str()); } -static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jIface, - jstring jCommand) +static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jCommand) { - ScopedUtfChars ifname(env, jIface); ScopedUtfChars command(env, jCommand); if (command.c_str() == NULL) { return -1; } if (DBG) ALOGD("doInt: %s", command.c_str()); - return doIntCommand(ifname.c_str(), "%s", command.c_str()); + return doIntCommand("%s", command.c_str()); } -static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jIface, - jstring jCommand) +static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jCommand) { - ScopedUtfChars ifname(env, jIface); - ScopedUtfChars command(env, jCommand); if (command.c_str() == NULL) { return NULL; } if (DBG) ALOGD("doString: %s", command.c_str()); - return doStringCommand(env, ifname.c_str(), "%s", command.c_str()); + return doStringCommand(env, "%s", command.c_str()); } @@ -205,17 +195,13 @@ static JNINativeMethod gWifiMethods[] = { { "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver }, { "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant }, { "killSupplicant", "(Z)Z", (void *)android_net_wifi_killSupplicant }, - { "connectToSupplicant", "(Ljava/lang/String;)Z", - (void *)android_net_wifi_connectToSupplicant }, - { "closeSupplicantConnection", "(Ljava/lang/String;)V", + { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant }, + { "closeSupplicantConnectionNative", "()V", (void *)android_net_wifi_closeSupplicantConnection }, - { "waitForEvent", "(Ljava/lang/String;)Ljava/lang/String;", - (void*) android_net_wifi_waitForEvent }, - { "doBooleanCommand", "(Ljava/lang/String;Ljava/lang/String;)Z", - (void*) android_net_wifi_doBooleanCommand }, - { "doIntCommand", "(Ljava/lang/String;Ljava/lang/String;)I", - (void*) android_net_wifi_doIntCommand }, - { "doStringCommand", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent }, + { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand }, + { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand }, + { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*) android_net_wifi_doStringCommand }, }; diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 61ace4a..f5eb389 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -220,6 +220,8 @@ static void read_mapinfo(FILE *fp, stats_t* stats) } else { whichHeap = HEAP_ASHMEM; } + } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) { + whichHeap = HEAP_NATIVE; } else if (strncmp(name, "[stack", 6) == 0) { whichHeap = HEAP_STACK; } else if (strncmp(name, "/dev/", 5) == 0) { @@ -246,6 +248,8 @@ static void read_mapinfo(FILE *fp, stats_t* stats) } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) { whichHeap = HEAP_ART; is_swappable = true; + } else if (strncmp(name, "[anon:", 6) == 0) { + whichHeap = HEAP_UNKNOWN; } else if (nameLen > 0) { whichHeap = HEAP_UNKNOWN_MAP; } else if (start == prevEnd && prevHeap == HEAP_SO) { diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp index 0aaa2b1..d1245da 100644 --- a/core/jni/android_os_FileUtils.cpp +++ b/core/jni/android_os_FileUtils.cpp @@ -33,46 +33,6 @@ namespace android { -jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz, - jstring file, jint mode, - jint uid, jint gid) -{ - const jchar* str = env->GetStringCritical(file, 0); - String8 file8; - if (str) { - file8 = String8(str, env->GetStringLength(file)); - env->ReleaseStringCritical(file, str); - } - if (file8.size() <= 0) { - return ENOENT; - } - if (uid >= 0 || gid >= 0) { - int res = chown(file8.string(), uid, gid); - if (res != 0) { - return errno; - } - } - return chmod(file8.string(), mode) == 0 ? 0 : errno; -} - -jint android_os_FileUtils_getUid(JNIEnv* env, jobject clazz, jstring file) -{ - struct stat stats; - const jchar* str = env->GetStringCritical(file, 0); - String8 file8; - if (str) { - file8 = String8(str, env->GetStringLength(file)); - env->ReleaseStringCritical(file, str); - } - if (file8.size() <= 0) { - return ENOENT; - } - if (stat(file8.string(), &stats) < 0) { - return -1; - } - return stats.st_uid; -} - jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path) { if (path == NULL) { @@ -95,8 +55,6 @@ jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring pat } static const JNINativeMethod methods[] = { - {"setPermissions", "(Ljava/lang/String;III)I", (void*)android_os_FileUtils_setPermissions}, - {"getUid", "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getUid}, {"getFatVolumeId", "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getFatVolumeId}, }; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index e5e3a2f..19f56cd 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -333,6 +333,12 @@ static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj, return javaObjectForIBinder(env, token); } +static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) { + sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); + if (token == NULL) return; + SurfaceComposerClient::destroyDisplay(token); +} + static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz, jobject tokenObj, jint nativeSurfaceObject) { sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); @@ -441,6 +447,8 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetBuiltInDisplay }, {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;", (void*)nativeCreateDisplay }, + {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V", + (void*)nativeDestroyDisplay }, {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V", (void*)nativeSetDisplaySurface }, {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V", diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png Binary files differindex cfbbd8d..0c13339 100644 --- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png +++ b/core/res/res/drawable-hdpi/stat_sys_adb_am.png diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png Binary files differindex 4862919..f0a5089 100644 --- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png +++ b/core/res/res/drawable-mdpi/stat_sys_adb_am.png diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png Binary files differindex 63b53b8..4fd0e3c 100644 --- a/core/res/res/drawable-nodpi/platlogo.png +++ b/core/res/res/drawable-nodpi/platlogo.png diff --git a/core/res/res/drawable-nodpi/platlogo_alt.png b/core/res/res/drawable-nodpi/platlogo_alt.png Binary files differdeleted file mode 100644 index f46c6c6..0000000 --- a/core/res/res/drawable-nodpi/platlogo_alt.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png Binary files differindex 576ae24..789a3f5 100644 --- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png +++ b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b9840e2..0908f36 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -26,7 +26,7 @@ <item><xliff:g id="id">ime</xliff:g></item> <item><xliff:g id="id">sync_failing</xliff:g></item> <item><xliff:g id="id">sync_active</xliff:g></item> - <item><xliff:g id="id">gps</xliff:g></item> + <item><xliff:g id="id">location</xliff:g></item> <item><xliff:g id="id">bluetooth</xliff:g></item> <item><xliff:g id="id">nfc</xliff:g></item> <item><xliff:g id="id">tty</xliff:g></item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 0bfed1b..04cdac9 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -985,7 +985,6 @@ <java-symbol type="drawable" name="jog_tab_target_gray" /> <java-symbol type="drawable" name="picture_emergency" /> <java-symbol type="drawable" name="platlogo" /> - <java-symbol type="drawable" name="platlogo_alt" /> <java-symbol type="drawable" name="stat_notify_sync_error" /> <java-symbol type="drawable" name="stat_notify_wifi_in_range" /> <java-symbol type="drawable" name="stat_notify_rssi_in_range" /> diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd index ebd7c25..6ec1e1b 100644 --- a/docs/html/guide/topics/providers/content-provider-creating.jd +++ b/docs/html/guide/topics/providers/content-provider-creating.jd @@ -680,7 +680,7 @@ public class ExampleProvider extends ContentProvider * Notice that the database itself isn't created or opened * until SQLiteOpenHelper.getWritableDatabase is called */ - mOpenHelper = new SQLiteOpenHelper( + mOpenHelper = new MainDatabaseHelper( getContext(), // the application context DBNAME, // the name of the database) null, // uses the default SQLite cursor diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd index e0c87d7..3b1292e 100644 --- a/docs/html/guide/topics/ui/notifiers/notifications.jd +++ b/docs/html/guide/topics/ui/notifiers/notifications.jd @@ -285,7 +285,7 @@ page.title=Notifications <p> Starting an {@link android.app.Activity} when the user clicks the notification is the most common action scenario. You can also start an {@link android.app.Activity} when the user - dismisses an {@link android.app.Activity}. In Android 4.1 and later, you can start an + dismisses a notification. In Android 4.1 and later, you can start an {@link android.app.Activity} from an action button. To learn more, read the reference guide for {@link android.support.v4.app.NotificationCompat.Builder}. </p> diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index fdec22b..0ea4074 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -114,9 +114,13 @@ public class Canvas { * canvas. */ public Canvas() { - // 0 means no native bitmap - mNativeCanvas = initRaster(0); - mFinalizer = new CanvasFinalizer(mNativeCanvas); + if (!isHardwareAccelerated()) { + // 0 means no native bitmap + mNativeCanvas = initRaster(0); + mFinalizer = new CanvasFinalizer(mNativeCanvas); + } else { + mFinalizer = null; + } } /** @@ -1646,7 +1650,9 @@ public class Canvas { */ public void drawPicture(Picture picture) { picture.endRecording(); - native_drawPicture(mNativeCanvas, picture.ni()); + int restoreCount = save(); + picture.draw(this); + restoreToCount(restoreCount); } /** @@ -1831,7 +1837,5 @@ public class Canvas { float hOffset, float vOffset, int flags, int paint); - private static native void native_drawPicture(int nativeCanvas, - int nativePicture); private static native void finalizer(int nativeCanvas); } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 331cf6e..69d9916 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -431,6 +431,8 @@ public class Paint { mRasterizer = paint.mRasterizer; if (paint.mShader != null) { mShader = paint.mShader.copy(); + } else { + mShader = null; } mTypeface = paint.mTypeface; mXfermode = paint.mXfermode; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index d1bae1e..707f662 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1112,8 +1112,6 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); - - finishDrawTexture(); } void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { @@ -1256,8 +1254,6 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { GL_UNSIGNED_SHORT, NULL)); } - finishDrawTexture(); - #if DEBUG_LAYERS_AS_REGIONS drawRegionRects(layer->region); #endif @@ -2021,9 +2017,6 @@ void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) { mCaches.bindPositionVertexPointer(force, vertices, gVertexStride); } -void OpenGLRenderer::finishDrawTexture() { -} - /////////////////////////////////////////////////////////////////////////////// // Drawing /////////////////////////////////////////////////////////////////////////////// @@ -2308,8 +2301,6 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes glDrawArrays(GL_TRIANGLES, 0, count); - finishDrawTexture(); - int slot = mCaches.currentProgram->getAttrib("colors"); if (slot >= 0) { glDisableVertexAttribArray(slot); @@ -3134,8 +3125,6 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { mesh += (drawCount / 6) * 4; } - finishDrawTexture(); - #if DEBUG_LAYERS_AS_REGIONS drawRegionRects(layer->region); #endif @@ -3270,8 +3259,6 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture, setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); - - finishDrawTexture(); } // Same values used by Skia @@ -3488,8 +3475,6 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b setupDrawMesh(vertices, texCoords, vbo); glDrawArrays(drawMode, 0, elementsCount); - - finishDrawTexture(); } void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom, @@ -3515,8 +3500,6 @@ void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, setupDrawMeshIndices(vertices, texCoords, vbo); glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL); - - finishDrawTexture(); } void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom, @@ -3546,8 +3529,6 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f setupDrawMesh(vertices, texCoords); glDrawArrays(drawMode, 0, elementsCount); - - finishDrawTexture(); } void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 2f8a2f0..1c3bfdc 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -1003,7 +1003,6 @@ private: void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors); void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0); void setupDrawIndexedVertices(GLvoid* vertices); - void finishDrawTexture(); void accountForClear(SkXfermode::Mode mode); bool updateLayer(Layer* layer, bool inFrame); diff --git a/location/java/android/location/FusedBatchOptions.aidl b/location/java/android/location/FusedBatchOptions.aidl new file mode 100644 index 0000000..94cb6e1 --- /dev/null +++ b/location/java/android/location/FusedBatchOptions.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +parcelable FusedBatchOptions;
\ No newline at end of file diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java new file mode 100644 index 0000000..623d707 --- /dev/null +++ b/location/java/android/location/FusedBatchOptions.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A data class representing a set of options to configure batching sessions. + * @hide + */ +public class FusedBatchOptions implements Parcelable { + private volatile long mPeriodInNS = 0; + private volatile int mSourcesToUse = 0; + private volatile int mFlags = 0; + + // the default value is set to request fixes at no cost + private volatile double mMaxPowerAllocationInMW = 0; + + /* + * Getters and setters for properties needed to hold the options. + */ + public void setMaxPowerAllocationInMW(double value) { + mMaxPowerAllocationInMW = value; + } + + public double getMaxPowerAllocationInMW() { + return mMaxPowerAllocationInMW; + } + + public void setPeriodInNS(long value) { + mPeriodInNS = value; + } + + public long getPeriodInNS() { + return mPeriodInNS; + } + + public void setSourceToUse(int source) { + mSourcesToUse |= source; + } + + public void resetSourceToUse(int source) { + mSourcesToUse &= ~source; + } + + public boolean isSourceToUseSet(int source) { + return (mSourcesToUse & source) != 0; + } + + public int getSourcesToUse() { + return mSourcesToUse; + } + + public void setFlag(int flag) { + mFlags |= flag; + } + + public void resetFlag(int flag) { + mFlags &= ~flag; + } + + public boolean isFlagSet(int flag) { + return (mFlags & flag) != 0; + } + + public int getFlags() { + return mFlags; + } + + /** + * Definition of enum flag sets needed by this class. + * Such values need to be kept in sync with the ones in fused_location.h + */ + public static final class SourceTechnologies { + public static int GNSS = 1<<0; + public static int WIFI = 1<<1; + public static int SENSORS = 1<<2; + public static int CELL = 1<<3; + public static int BLUETOOTH = 1<<4; + } + + public static final class BatchFlags { + public static int WAKEUP_ON_FIFO_FULL = 1<<0; + public static int CALLBACK_ON_LOCATION_FIX = 1<<1; + } + + /* + * Method definitions to support Parcelable operations. + */ + public static final Parcelable.Creator<FusedBatchOptions> CREATOR = + new Parcelable.Creator<FusedBatchOptions>() { + @Override + public FusedBatchOptions createFromParcel(Parcel parcel) { + FusedBatchOptions options = new FusedBatchOptions(); + options.setMaxPowerAllocationInMW(parcel.readDouble()); + options.setPeriodInNS(parcel.readLong()); + options.setSourceToUse(parcel.readInt()); + options.setFlag(parcel.readInt()); + return options; + } + + @Override + public FusedBatchOptions[] newArray(int size) { + return new FusedBatchOptions[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeDouble(mMaxPowerAllocationInMW); + parcel.writeLong(mPeriodInNS); + parcel.writeInt(mSourcesToUse); + parcel.writeInt(mFlags); + } +} diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/location/java/android/location/IFusedGeofenceHardware.aidl new file mode 100644 index 0000000..9dbf1f4 --- /dev/null +++ b/location/java/android/location/IFusedGeofenceHardware.aidl @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/license/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.location; + +import android.location.Geofence; + +/** + * Fused Geofence Hardware interface. + * + * <p>This interface is the basic set of supported functionality by Fused Hardware modules that offer + * Geofencing capabilities. + * + * All operations are asynchronous and the status codes can be obtained via a set of callbacks. + * + * @hide + */ +interface IFusedGeofenceHardware { + /** + * Flags if the interface functionality is supported by the platform. + * + * @return true if the functionality is supported, false otherwise. + */ + boolean isSupported(); + + /** + * Adds a given list of geofences to the system. + * + * @param geofenceIdsArray The list of geofence Ids to add. + * @param geofencesArray the list of geofences to add. + */ + // TODO: [GeofenceIntegration] GeofenceHardwareRequest is not a parcelable class exposed in aidl + void addGeofences(in int[] geofenceIdsArray, in Geofence[] geofencesArray); + + /** + * Removes a give list of geofences from the system. + * + * @param geofences The list of geofences to remove. + */ + void removeGeofences(in int[] geofenceIds); + + /** + * Pauses monitoring a particular geofence. + * + * @param geofenceId The geofence to pause monitoring. + */ + void pauseMonitoringGeofence(in int geofenceId); + + /** + * Resumes monitoring a particular geofence. + * + * @param geofenceid The geofence to resume monitoring. + * @param transitionsToMonitor The transitions to monitor upon resume. + * + * Remarks: keep naming of geofence request options consistent with the naming used in + * GeofenceHardwareRequest + */ + void resumeMonitoringGeofence(in int geofenceId, in int monitorTransitions); + + /** + * Modifies the request options if a geofence that is already known by the + * system. + * + * @param geofenceId The geofence to modify. + * @param lastTransition The last known transition state of + * the geofence. + * @param monitorTransitions The set of transitions to monitor. + * @param notificationResponsiveness The notification responsivness needed. + * @param unknownTimer The time span associated with the + * + * Remarks: keep the options as separate fields to be able to leverage the class + * GeofenceHardwareRequest without any changes + */ + void modifyGeofenceOptions( + in int geofenceId, + in int lastTransition, + in int monitorTransitions, + in int notificationResponsiveness, + in int unknownTimer); +} diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl new file mode 100644 index 0000000..8870d2a --- /dev/null +++ b/location/java/android/location/IFusedProvider.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.hardware.location.IFusedLocationHardware; + +/** + * Interface definition for Location providers that require FLP services. + * @hide + */ +interface IFusedProvider { + /** + * Provides access to a FusedLocationHardware instance needed for the provider to work. + * + * @param instance The FusedLocationHardware available for the provider to use. + */ + void onFusedLocationHardwareChange(in IFusedLocationHardware instance); +}
\ No newline at end of file diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 989178a..e5f1cf5 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -177,6 +177,17 @@ public class LocationManager { */ public static final String EXTRA_GPS_ENABLED = "enabled"; + /** + * Broadcast intent action indicating that a high power location requests + * has either started or stopped being active. The current state of + * active location requests should be read from AppOpsManager using + * {@code OP_MONITOR_HIGH_POWER_LOCATION}. + * + * @hide + */ + public static final String HIGH_POWER_REQUEST_CHANGE_ACTION = + "android.location.HIGH_POWER_REQUEST_CHANGE"; + // Map from LocationListeners to their associated ListenerTransport objects private HashMap<LocationListener,ListenerTransport> mListeners = new HashMap<LocationListener,ListenerTransport>(); diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java new file mode 100644 index 0000000..abea9fb --- /dev/null +++ b/location/lib/java/com/android/location/provider/FusedLocationHardware.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIOS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.provider; + +import android.hardware.location.IFusedLocationHardware; +import android.hardware.location.IFusedLocationHardwareSink; + +import android.location.Location; + +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Class that exposes IFusedLocationHardware functionality to unbundled services. + * Namely this is used by GmsCore Fused Location Provider. + */ +public final class FusedLocationHardware { + private final String TAG = "FusedLocationHardware"; + + private IFusedLocationHardware mLocationHardware; + ArrayList<FusedLocationHardwareSink> mSinkList = new ArrayList<FusedLocationHardwareSink>(); + + private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() { + @Override + public void onLocationAvailable(Location[] locations) { + dispatchLocations(locations); + } + + @Override + public void onDiagnosticDataAvailable(String data) { + dispatchDiagnosticData(data); + } + }; + + public FusedLocationHardware(IFusedLocationHardware locationHardware) { + mLocationHardware = locationHardware; + } + + /* + * Methods to provide a Facade for IFusedLocationHardware + */ + public void registerSink(FusedLocationHardwareSink sink) { + if(sink == null) { + return; + } + + boolean registerSink = false; + synchronized (mSinkList) { + // register only on first insertion + registerSink = mSinkList.size() == 0; + // guarantee uniqueness + if(!mSinkList.contains(sink)) { + mSinkList.add(sink); + } + } + + if(registerSink) { + try { + mLocationHardware.registerSink(mInternalSink); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at registerSink"); + } + } + } + + public void unregisterSink(FusedLocationHardwareSink sink) { + if(sink == null) { + return; + } + + boolean unregisterSink = false; + synchronized(mSinkList) { + mSinkList.remove(sink); + // unregister after the last sink + unregisterSink = mSinkList.size() == 0; + } + + if(unregisterSink) { + try { + mLocationHardware.unregisterSink(mInternalSink); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at unregisterSink"); + } + } + } + + public int getSupportedBatchSize() { + try { + return mLocationHardware.getSupportedBatchSize(); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at getSupportedBatchSize"); + return 0; + } + } + + public void startBatching(int id, GmsFusedBatchOptions batchOptions) { + try { + mLocationHardware.startBatching(id, batchOptions.getParcelableOptions()); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at startBatching"); + } + } + + public void stopBatching(int id) { + try { + mLocationHardware.stopBatching(id); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at stopBatching"); + } + } + + public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) { + try { + mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions()); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at updateBatchingOptions"); + } + } + + public void requestBatchOfLocations(int batchSizeRequest) { + try { + mLocationHardware.requestBatchOfLocations(batchSizeRequest); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at requestBatchOfLocations"); + } + } + + public boolean supportsDiagnosticDataInjection() { + try { + return mLocationHardware.supportsDiagnosticDataInjection(); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection"); + return false; + } + } + + public void injectDiagnosticData(String data) { + try { + mLocationHardware.injectDiagnosticData(data); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at injectDiagnosticData"); + } + } + + public boolean supportsDeviceContextInjection() { + try { + return mLocationHardware.supportsDeviceContextInjection(); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at supportsDeviceContextInjection"); + return false; + } + } + + public void injectDeviceContext(int deviceEnabledContext) { + try { + mLocationHardware.injectDeviceContext(deviceEnabledContext); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException at injectDeviceContext"); + } + } + + /* + * Helper methods + */ + private void dispatchLocations(Location[] locations) { + ArrayList<FusedLocationHardwareSink> sinks = null; + synchronized (mSinkList) { + sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList); + } + + for(FusedLocationHardwareSink sink : sinks) { + sink.onLocationAvailable(locations); + } + } + + private void dispatchDiagnosticData(String data) { + ArrayList<FusedLocationHardwareSink> sinks = null; + synchronized(mSinkList) { + sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList); + } + + for(FusedLocationHardwareSink sink : sinks) { + sink.onDiagnosticDataAvailable(data); + } + } +} diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java new file mode 100644 index 0000000..118b663 --- /dev/null +++ b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.provider; + +import android.location.Location; + +/** + * Base class for sinks to interact with FusedLocationHardware. + * This is mainly used by GmsCore Fused Provider. + */ +public abstract class FusedLocationHardwareSink { + /* + * Methods to provide a facade for IFusedLocationHardware + */ + public abstract void onLocationAvailable(Location[] locations); + public abstract void onDiagnosticDataAvailable(String data); +}
\ No newline at end of file diff --git a/location/lib/java/com/android/location/provider/FusedProvider.java b/location/lib/java/com/android/location/provider/FusedProvider.java new file mode 100644 index 0000000..bc9feef --- /dev/null +++ b/location/lib/java/com/android/location/provider/FusedProvider.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.provider; + +import android.hardware.location.IFusedLocationHardware; +import android.location.IFusedProvider; +import android.os.IBinder; + +/** + * Base class for Fused providers implemented as unbundled services. + * + * <p>Fused providers can be implemented as services and return the result of + * {@link com.android.location.provider.FusedProvider#getBinder()} in its getBinder() method. + * + * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain + * API stable. See README.txt in the root of this package for more information. + * + * @hide + */ +public abstract class FusedProvider { + private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() { + @Override + public void onFusedLocationHardwareChange(IFusedLocationHardware instance) { + setFusedLocationHardware(new FusedLocationHardware(instance)); + } + }; + + /** + * Gets the Binder associated with the provider. + * This is intended to be used for the onBind() method of a service that implements a fused + * service. + * + * @return The IBinder instance associated with the provider. + */ + public IBinder getBinder() { + return mProvider; + } + + /** + * Sets the FusedLocationHardware instance in the provider.. + * @param value The instance to set. This can be null in cases where the service connection + * is disconnected. + */ + public abstract void setFusedLocationHardware(FusedLocationHardware value); +} diff --git a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java new file mode 100644 index 0000000..fd3f402 --- /dev/null +++ b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.provider; + +import android.location.FusedBatchOptions; + +/** + * Class that exposes FusedBatchOptions to the GmsCore . + */ +public class GmsFusedBatchOptions { + private FusedBatchOptions mOptions = new FusedBatchOptions(); + + /* + * Methods that provide a facade for properties in FusedBatchOptions. + */ + public void setMaxPowerAllocationInMW(double value) { + mOptions.setMaxPowerAllocationInMW(value); + } + + public double getMaxPowerAllocationInMW() { + return mOptions.getMaxPowerAllocationInMW(); + } + + public void setPeriodInNS(long value) { + mOptions.setPeriodInNS(value); + } + + public long getPeriodInNS() { + return mOptions.getPeriodInNS(); + } + + public void setSourceToUse(int source) { + mOptions.setSourceToUse(source); + } + + public void resetSourceToUse(int source) { + mOptions.resetSourceToUse(source); + } + + public boolean isSourceToUseSet(int source) { + return mOptions.isSourceToUseSet(source); + } + + public int getSourcesToUse() { + return mOptions.getSourcesToUse(); + } + + public void setFlag(int flag) { + mOptions.setFlag(flag); + } + + public void resetFlag(int flag) { + mOptions.resetFlag(flag); + } + + public boolean isFlagSet(int flag) { + return mOptions.isFlagSet(flag); + } + + public int getFlags() { + return mOptions.getFlags(); + } + + /** + * Definition of enum flag sets needed by this class. + * Such values need to be kept in sync with the ones in fused_location.h + */ + + public static final class SourceTechnologies { + public static int GNSS = 1<<0; + public static int WIFI = 1<<1; + public static int SENSORS = 1<<2; + public static int CELL = 1<<3; + public static int BLUETOOTH = 1<<4; + } + + public static final class BatchFlags { + public static int WAKEUP_ON_FIFO_FULL = 1<<0; + public static int CALLBACK_ON_LOCATION_FIX = 1<<1; + } + + /* + * Method definitions for internal use. + */ + + /* + * @hide + */ + public FusedBatchOptions getParcelableOptions() { + return mOptions; + } +} diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 632334b..cf1238a 100644..100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -221,7 +221,7 @@ public class MtpDatabase { if (c != null) c.close(); if (db != null) db.close(); } - databaseFile.delete(); + context.deleteDatabase(devicePropertiesName); } } diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp index fdecda3..84dad8c 100644 --- a/media/mca/filterfw/native/core/gl_env.cpp +++ b/media/mca/filterfw/native/core/gl_env.cpp @@ -26,6 +26,8 @@ #include <string> #include <EGL/eglext.h> +#include <gui/GLConsumer.h> + namespace android { namespace filterfw { diff --git a/media/mca/filterfw/native/core/gl_env.h b/media/mca/filterfw/native/core/gl_env.h index 81e1e9d..a709638 100644 --- a/media/mca/filterfw/native/core/gl_env.h +++ b/media/mca/filterfw/native/core/gl_env.h @@ -31,6 +31,9 @@ #include <gui/Surface.h> namespace android { + +class GLConsumer; + namespace filterfw { class ShaderProgram; diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 8e7e087..a536acb 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -72,7 +72,7 @@ public class DocumentsActivity extends Activity { private final DisplayState mDisplayState = new DisplayState(); /** Current user navigation stack; empty implies recents. */ - private DocumentStack mStack; + private DocumentStack mStack = new DocumentStack(); /** Currently active search, overriding any stack. */ private String mCurrentSearch; diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2629b11..5e198a2 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -24,6 +24,7 @@ <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> <!-- Networking and telephony --> <uses-permission android:name="android.permission.BLUETOOTH" /> @@ -188,37 +189,6 @@ android:taskAffinity="com.android.systemui.net" android:excludeFromRecents="true" /> - <!-- started from ... somewhere --> - <activity - android:name=".BeanBag" - android:exported="true" - android:label="BeanBag" - android:icon="@drawable/redbean2" - android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen" - android:hardwareAccelerated="true" - android:launchMode="singleInstance" - android:excludeFromRecents="true"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="com.android.internal.category.PLATLOGO" /> -<!-- <category android:name="android.intent.category.LAUNCHER" />--> - </intent-filter> - </activity> - - <!-- Beans in space --> - <service - android:name=".BeanBagDream" - android:exported="true" - android:label="@string/jelly_bean_dream_name" - android:enabled="false" - > - <intent-filter> - <action android:name="android.service.dreams.DreamService" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </service> - <activity android:name=".Somnambulator" android:label="@string/start_dreams" android:icon="@mipmap/ic_launcher_dreams" diff --git a/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png Binary files differnew file mode 100644 index 0000000..3b952d0 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png Binary files differnew file mode 100644 index 0000000..657a612 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png Binary files differnew file mode 100644 index 0000000..a0ab991 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png Binary files differnew file mode 100644 index 0000000..80fc24b --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png b/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png Binary files differdeleted file mode 100644 index 47c89b1..0000000 --- a/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-nodpi/redbean0.png b/packages/SystemUI/res/drawable-nodpi/redbean0.png Binary files differdeleted file mode 100644 index b088939..0000000 --- a/packages/SystemUI/res/drawable-nodpi/redbean0.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-nodpi/redbean1.png b/packages/SystemUI/res/drawable-nodpi/redbean1.png Binary files differdeleted file mode 100644 index 8fc8d9d..0000000 --- a/packages/SystemUI/res/drawable-nodpi/redbean1.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-nodpi/redbean2.png b/packages/SystemUI/res/drawable-nodpi/redbean2.png Binary files differdeleted file mode 100644 index ef11ca8..0000000 --- a/packages/SystemUI/res/drawable-nodpi/redbean2.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-nodpi/redbeandroid.png b/packages/SystemUI/res/drawable-nodpi/redbeandroid.png Binary files differdeleted file mode 100644 index 9aa3f82..0000000 --- a/packages/SystemUI/res/drawable-nodpi/redbeandroid.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png Binary files differnew file mode 100644 index 0000000..fd8ad64 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 0073e60..33a85c3 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -418,6 +418,9 @@ <!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] --> <string name="gps_notification_found_text">Location set by GPS</string> + <!-- Accessibility text describing the presence of active location requests by one or more apps --> + <string name="accessibility_location_active">Location requests active</string> + <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_clear_all">Clear all notifications.</string> diff --git a/packages/SystemUI/src/com/android/systemui/BeanBag.java b/packages/SystemUI/src/com/android/systemui/BeanBag.java deleted file mode 100644 index a396759..0000000 --- a/packages/SystemUI/src/com/android/systemui/BeanBag.java +++ /dev/null @@ -1,412 +0,0 @@ -/*); - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui; - -import android.animation.TimeAnimator; -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.Paint; -import android.graphics.drawable.BitmapDrawable; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; - -import java.util.Random; - -public class BeanBag extends Activity { - final static boolean DEBUG = false; - - public static class Board extends FrameLayout - { - static Random sRNG = new Random(); - - static float lerp(float a, float b, float f) { - return (b-a)*f + a; - } - - static float randfrange(float a, float b) { - return lerp(a, b, sRNG.nextFloat()); - } - - static int randsign() { - return sRNG.nextBoolean() ? 1 : -1; - } - - static boolean flip() { - return sRNG.nextBoolean(); - } - - static float mag(float x, float y) { - return (float) Math.sqrt(x*x+y*y); - } - - static float clamp(float x, float a, float b) { - return ((x<a)?a:((x>b)?b:x)); - } - - static float dot(float x1, float y1, float x2, float y2) { - return x1*x2+y1+y2; - } - - static <E> E pick(E[] array) { - if (array.length == 0) return null; - return array[sRNG.nextInt(array.length)]; - } - - static int pickInt(int[] array) { - if (array.length == 0) return 0; - return array[sRNG.nextInt(array.length)]; - } - - static int NUM_BEANS = 40; - static float MIN_SCALE = 0.2f; - static float MAX_SCALE = 1f; - - static float LUCKY = 0.001f; - - static int MAX_RADIUS = (int)(576 * MAX_SCALE); - - static int BEANS[] = { - R.drawable.redbean0, - R.drawable.redbean0, - R.drawable.redbean0, - R.drawable.redbean0, - R.drawable.redbean1, - R.drawable.redbean1, - R.drawable.redbean2, - R.drawable.redbean2, - R.drawable.redbeandroid, - }; - - static int COLORS[] = { - 0xFF00CC00, - 0xFFCC0000, - 0xFF0000CC, - 0xFFFFFF00, - 0xFFFF8000, - 0xFF00CCFF, - 0xFFFF0080, - 0xFF8000FF, - 0xFFFF8080, - 0xFF8080FF, - 0xFFB0C0D0, - 0xFFDDDDDD, - 0xFF333333, - }; - - public class Bean extends ImageView { - public static final float VMAX = 1000.0f; - public static final float VMIN = 100.0f; - - public float x, y, a; - - public float va; - public float vx, vy; - - public float r; - - public float z; - - public int h,w; - - public boolean grabbed; - public float grabx, graby; - public long grabtime; - private float grabx_offset, graby_offset; - - public Bean(Context context, AttributeSet as) { - super(context, as); - } - - public String toString() { - return String.format("<bean (%.1f, %.1f) (%d x %d)>", - getX(), getY(), getWidth(), getHeight()); - } - - private void pickBean() { - int beanId = pickInt(BEANS); - if (randfrange(0,1) <= LUCKY) { - beanId = R.drawable.jandycane; - } - BitmapDrawable bean = (BitmapDrawable) getContext().getResources().getDrawable(beanId); - Bitmap beanBits = bean.getBitmap(); - h=beanBits.getHeight(); - w=beanBits.getWidth(); - - if (DEBUG) { - bean.setAlpha(0x80); - } - this.setImageDrawable(bean); - - Paint pt = new Paint(); - final int color = pickInt(COLORS); - ColorMatrix CM = new ColorMatrix(); - float[] M = CM.getArray(); - // we assume the color information is in the red channel - /* R */ M[0] = (float)((color & 0x00FF0000) >> 16) / 0xFF; - /* G */ M[5] = (float)((color & 0x0000FF00) >> 8) / 0xFF; - /* B */ M[10] = (float)((color & 0x000000FF)) / 0xFF; - pt.setColorFilter(new ColorMatrixColorFilter(M)); - setLayerType(View.LAYER_TYPE_HARDWARE, (beanId == R.drawable.jandycane) ? null : pt); - } - - public void reset() { - pickBean(); - - final float scale = lerp(MIN_SCALE,MAX_SCALE,z); - setScaleX(scale); setScaleY(scale); - - r = 0.3f*Math.max(h,w)*scale; - - a=(randfrange(0,360)); - va = randfrange(-30,30); - - vx = randfrange(-40,40) * z; - vy = randfrange(-40,40) * z; - final float boardh = boardHeight; - final float boardw = boardWidth; - //android.util.Log.d("BeanBag", "reset: w="+w+" h="+h); - if (flip()) { - x=(vx < 0 ? boardw+2*r : -r*4f); - y=(randfrange(0, boardh-3*r)*0.5f + ((vy < 0)?boardh*0.5f:0)); - } else { - y=(vy < 0 ? boardh+2*r : -r*4f); - x=(randfrange(0, boardw-3*r)*0.5f + ((vx < 0)?boardw*0.5f:0)); - } - } - - public void update(float dt) { - if (grabbed) { -// final float interval = (SystemClock.uptimeMillis() - grabtime) / 1000f; - vx = (vx * 0.75f) + ((grabx - x) / dt) * 0.25f; - x = grabx; - vy = (vy * 0.75f) + ((graby - y) / dt) * 0.25f;; - y = graby; - } else { - x = (x + vx * dt); - y = (y + vy * dt); - a = (a + va * dt); - } - } - - public float overlap(Bean other) { - final float dx = (x - other.x); - final float dy = (y - other.y); - return mag(dx, dy) - r - other.r; - } - - @Override - public boolean onTouchEvent(MotionEvent e) { - switch (e.getAction()) { - case MotionEvent.ACTION_DOWN: - grabbed = true; - grabx_offset = e.getRawX() - x; - graby_offset = e.getRawY() - y; - va = 0; - // fall - case MotionEvent.ACTION_MOVE: - grabx = e.getRawX() - grabx_offset; - graby = e.getRawY() - graby_offset; - grabtime = e.getEventTime(); - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - grabbed = false; - float a = randsign() * clamp(mag(vx, vy) * 0.33f, 0, 1080f); - va = randfrange(a*0.5f, a); - break; - } - return true; - } - } - - TimeAnimator mAnim; - private int boardWidth; - private int boardHeight; - - public Board(Context context, AttributeSet as) { - super(context, as); - - setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); - - setWillNotDraw(!DEBUG); - } - - private void reset() { -// android.util.Log.d("Nyandroid", "board reset"); - removeAllViews(); - - final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - - for(int i=0; i<NUM_BEANS; i++) { - Bean nv = new Bean(getContext(), null); - addView(nv, wrap); - nv.z = ((float)i/NUM_BEANS); - nv.z *= nv.z; - nv.reset(); - nv.x = (randfrange(0, boardWidth)); - nv.y = (randfrange(0, boardHeight)); - } - - if (mAnim != null) { - mAnim.cancel(); - } - mAnim = new TimeAnimator(); - mAnim.setTimeListener(new TimeAnimator.TimeListener() { - private long lastPrint = 0; - public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { - if (DEBUG && totalTime - lastPrint > 5000) { - lastPrint = totalTime; - for (int i=0; i<getChildCount(); i++) { - android.util.Log.d("BeanBag", "bean " + i + ": " + getChildAt(i)); - } - } - - for (int i=0; i<getChildCount(); i++) { - View v = getChildAt(i); - if (!(v instanceof Bean)) continue; - Bean nv = (Bean) v; - nv.update(deltaTime / 1000f); - - for (int j=i+1; j<getChildCount(); j++) { - View v2 = getChildAt(j); - if (!(v2 instanceof Bean)) continue; - Bean nv2 = (Bean) v2; - final float overlap = nv.overlap(nv2); - } - - nv.setRotation(nv.a); - nv.setX(nv.x-nv.getPivotX()); - nv.setY(nv.y-nv.getPivotY()); - - if ( nv.x < - MAX_RADIUS - || nv.x > boardWidth + MAX_RADIUS - || nv.y < -MAX_RADIUS - || nv.y > boardHeight + MAX_RADIUS) - { - nv.reset(); - } - } - - if (DEBUG) invalidate(); - } - }); - } - - @Override - protected void onSizeChanged (int w, int h, int oldw, int oldh) { - super.onSizeChanged(w,h,oldw,oldh); - boardWidth = w; - boardHeight = h; -// android.util.Log.d("Nyandroid", "resized: " + w + "x" + h); - } - - public void startAnimation() { - stopAnimation(); - if (mAnim == null) { - post(new Runnable() { public void run() { - reset(); - startAnimation(); - } }); - } else { - mAnim.start(); - } - } - - public void stopAnimation() { - if (mAnim != null) mAnim.cancel(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - stopAnimation(); - } - - @Override - public boolean isOpaque() { - return false; - } - - @Override - public void onDraw(Canvas c) { - if (DEBUG) { - //android.util.Log.d("BeanBag", "onDraw"); - Paint pt = new Paint(); - pt.setAntiAlias(true); - pt.setStyle(Paint.Style.STROKE); - pt.setColor(0xFFFF0000); - pt.setStrokeWidth(4.0f); - c.drawRect(0, 0, getWidth(), getHeight(), pt); - pt.setColor(0xFFFFCC00); - pt.setStrokeWidth(1.0f); - for (int i=0; i<getChildCount(); i++) { - Bean b = (Bean) getChildAt(i); - final float a = (360-b.a)/180f*3.14159f; - final float tx = b.getTranslationX(); - final float ty = b.getTranslationY(); - c.drawCircle(b.x, b.y, b.r, pt); - c.drawCircle(tx, ty, 4, pt); - c.drawLine(b.x, b.y, (float)(b.x+b.r*Math.sin(a)), (float)(b.y+b.r*Math.cos(a)), pt); - } - } - } - } - - private Board mBoard; - - @Override - public void onStart() { - super.onStart(); - - // ACHIEVEMENT UNLOCKED - PackageManager pm = getPackageManager(); - pm.setComponentEnabledSetting(new ComponentName(this, BeanBagDream.class), - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); - - getWindow().addFlags( - WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - ); - mBoard = new Board(this, null); - setContentView(mBoard); - } - - @Override - public void onPause() { - super.onPause(); - mBoard.stopAnimation(); - } - - @Override - public void onResume() { - super.onResume(); - mBoard.startAnimation(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java deleted file mode 100644 index 39e4727..0000000 --- a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui; - -import android.service.dreams.DreamService; - -import com.android.systemui.BeanBag.Board; - -public class BeanBagDream extends DreamService { - - private Board mBoard; - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - setInteractive(true); - setFullscreen(true); - mBoard = new Board(this, null); - setContentView(mBoard); - } - - @Override - public void onDreamingStarted() { - super.onDreamingStarted(); - mBoard.startAnimation(); - } - - @Override - public void onDreamingStopped() { - mBoard.stopAnimation(); - super.onDreamingStopped(); - } -} 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 a92703c..c914a34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -129,6 +129,8 @@ public class PhoneStatusBar extends BaseStatusBar { private static final int STATUS_OR_NAV_TRANSIENT = View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; + private static final int TRANSIENT_NAV_HIDING = + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT; private static final long AUTOHIDE_TIMEOUT_MS = 3000; private static final float TRANSPARENT_ALPHA = 0.7f; @@ -1955,14 +1957,12 @@ public class PhoneStatusBar extends BaseStatusBar { // update hiding navigation confirmation if (mNavigationBarView != null) { - final int hidingNav = - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT; - boolean oldHidingNav = (oldVal & hidingNav) != 0; - boolean newHidingNav = (newVal & hidingNav) != 0; - if (!oldHidingNav && newHidingNav) { + boolean oldShowConfirm = (oldVal & TRANSIENT_NAV_HIDING) == TRANSIENT_NAV_HIDING; + boolean newShowConfirm = (newVal & TRANSIENT_NAV_HIDING) == TRANSIENT_NAV_HIDING; + if (!oldShowConfirm && newShowConfirm) { mHidingNavigationConfirmationDismissed = false; } - setHidingNavigationConfirmationVisible(newHidingNav); + setHidingNavigationConfirmationVisible(newShowConfirm); } // send updated sysui visibility to window manager diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index 3f8043d..91ddf0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -16,10 +16,8 @@ package com.android.systemui.statusbar.policy; -import android.app.INotificationManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; +import android.app.AppOpsManager; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -28,36 +26,39 @@ import android.content.IntentFilter; import android.database.ContentObserver; import android.location.LocationManager; import android.os.Handler; -import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import com.android.systemui.R; import java.util.ArrayList; +import java.util.List; +/** + * A controller to manage changes of location related states and update the views accordingly. + */ public class LocationController extends BroadcastReceiver { - private static final String TAG = "StatusBar.LocationController"; + // The name of the placeholder corresponding to the location request status icon. + // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml. + private static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location"; + private static final int LOCATION_STATUS_ICON_ID + = R.drawable.stat_sys_device_access_location_found; - private static final int GPS_NOTIFICATION_ID = 374203-122084; + private static final int[] mHighPowerRequestAppOpArray + = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION}; private Context mContext; - private INotificationManager mNotificationService; + private AppOpsManager mAppOpsManager; + private StatusBarManager mStatusBarManager; + + private boolean mAreActiveLocationRequests; + private boolean mIsAirplaneMode; - private ArrayList<LocationGpsStateChangeCallback> mChangeCallbacks = - new ArrayList<LocationGpsStateChangeCallback>(); private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks = new ArrayList<LocationSettingsChangeCallback>(); /** - * A callback for change in gps status (enabled/disabled, have lock, etc). - */ - public interface LocationGpsStateChangeCallback { - public void onLocationGpsStateChanged(boolean inUse, String description); - } - - /** * A callback for change in location settings (the user has enabled/disabled location). */ public interface LocationSettingsChangeCallback { @@ -74,13 +75,15 @@ public class LocationController extends BroadcastReceiver { mContext = context; IntentFilter filter = new IntentFilter(); - filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION); - filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION); + filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); + // Listen for a change in the airplane mode setting so we can defensively turn off the + // high power location icon when radios are disabled. + filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); context.registerReceiver(this, filter); - NotificationManager nm = (NotificationManager)context.getSystemService( - Context.NOTIFICATION_SERVICE); - mNotificationService = nm.getService(); + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mStatusBarManager + = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); // Register to listen for changes to the location settings context.getContentResolver().registerContentObserver( @@ -94,13 +97,11 @@ public class LocationController extends BroadcastReceiver { } } }); - } - /** - * Add a callback to listen for changes in gps status. - */ - public void addStateChangedCallback(LocationGpsStateChangeCallback cb) { - mChangeCallbacks.add(cb); + // Examine the current location state and initialize the status view. + updateActiveLocationRequests(); + updateAirplaneMode(); + refreshViews(); } /** @@ -145,76 +146,77 @@ public class LocationController extends BroadcastReceiver { return isGpsEnabled || isNetworkEnabled; } - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false); - - boolean visible; - int iconId, textResId; - - if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) { - // GPS is getting fixes - iconId = com.android.internal.R.drawable.stat_sys_gps_on; - textResId = R.string.gps_notification_found_text; - visible = true; - } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) { - // GPS is off - visible = false; - iconId = textResId = 0; + /** + * Returns true if there currently exist active high power location requests. + */ + private boolean areActiveHighPowerLocationRequests() { + List<AppOpsManager.PackageOps> packages + = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray); + // AppOpsManager can return null when there is no requested data. + if (packages != null) { + final int numPackages = packages.size(); + for (int packageInd = 0; packageInd < numPackages; packageInd++) { + AppOpsManager.PackageOps packageOp = packages.get(packageInd); + List<AppOpsManager.OpEntry> opEntries = packageOp.getOps(); + if (opEntries != null) { + final int numOps = opEntries.size(); + for (int opInd = 0; opInd < numOps; opInd++) { + AppOpsManager.OpEntry opEntry = opEntries.get(opInd); + // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because + // of the mHighPowerRequestAppOpArray filter, but checking defensively. + if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) { + if (opEntry.isRunning()) { + return true; + } + } + } + } + } + } + + return false; + } + + // Updates the status view based on the current state of location requests and airplane mode. + private void refreshViews() { + // The airplane mode check is defensive - there shouldn't be any active high power + // location requests when airplane mode is on. + if (!mIsAirplaneMode && mAreActiveLocationRequests) { + mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0, + mContext.getString(R.string.accessibility_location_active)); } else { - // GPS is on, but not receiving fixes - iconId = R.drawable.stat_sys_gps_acquiring_anim; - textResId = R.string.gps_notification_searching_text; - visible = true; + mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER); } + } - try { - if (visible) { - Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0, - gpsIntent, 0, null, UserHandle.CURRENT); - String text = mContext.getText(textResId).toString(); - - Notification n = new Notification.Builder(mContext) - .setSmallIcon(iconId) - .setContentTitle(text) - .setOngoing(true) - .setContentIntent(pendingIntent) - .getNotification(); - - // Notification.Builder will helpfully fill these out for you no matter what you do - n.tickerView = null; - n.tickerText = null; - - n.priority = Notification.PRIORITY_HIGH; - - int[] idOut = new int[1]; - mNotificationService.enqueueNotificationWithTag( - mContext.getPackageName(), mContext.getBasePackageName(), - null, - GPS_NOTIFICATION_ID, - n, - idOut, - UserHandle.USER_ALL); - - for (LocationGpsStateChangeCallback cb : mChangeCallbacks) { - cb.onLocationGpsStateChanged(true, text); - } - } else { - mNotificationService.cancelNotificationWithTag( - mContext.getPackageName(), null, - GPS_NOTIFICATION_ID, UserHandle.USER_ALL); + // Reads the active location requests and updates the status view if necessary. + private void updateActiveLocationRequests() { + boolean hadActiveLocationRequests = mAreActiveLocationRequests; + mAreActiveLocationRequests = areActiveHighPowerLocationRequests(); + if (mAreActiveLocationRequests != hadActiveLocationRequests) { + refreshViews(); + } + } - for (LocationGpsStateChangeCallback cb : mChangeCallbacks) { - cb.onLocationGpsStateChanged(false, null); - } - } - } catch (android.os.RemoteException ex) { - // well, it was worth a shot + // Reads the airplane mode setting and updates the status view if necessary. + private void updateAirplaneMode() { + boolean wasAirplaneMode = mIsAirplaneMode; + // TODO This probably warrants a utility method in Settings.java. + mIsAirplaneMode = (Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) == 1); + if (mIsAirplaneMode != wasAirplaneMode) { + refreshViews(); } } -} + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) { + updateActiveLocationRequests(); + } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { + updateAirplaneMode(); + } + } +} diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java index 81572c5..7af95f3 100644 --- a/services/java/com/android/server/AppOpsService.java +++ b/services/java/com/android/server/AppOpsService.java @@ -426,12 +426,14 @@ public class AppOpsService extends IAppOpsService.Stub { HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null; synchronized (this) { boolean changed = false; - for (int i=0; i<mUidOps.size(); i++) { + for (int i=mUidOps.size()-1; i>=0; i--) { HashMap<String, Ops> packages = mUidOps.valueAt(i); - for (Map.Entry<String, Ops> ent : packages.entrySet()) { + Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, Ops> ent = it.next(); String packageName = ent.getKey(); Ops pkgOps = ent.getValue(); - for (int j=0; j<pkgOps.size(); j++) { + for (int j=pkgOps.size()-1; j>=0; j--) { Op curOp = pkgOps.valueAt(j); if (curOp.mode != AppOpsManager.MODE_ALLOWED) { curOp.mode = AppOpsManager.MODE_ALLOWED; @@ -440,9 +442,17 @@ public class AppOpsService extends IAppOpsService.Stub { mOpModeWatchers.get(curOp.op)); callbacks = addCallbacks(callbacks, packageName, curOp.op, mPackageModeWatchers.get(packageName)); - pruneOp(curOp, mUidOps.keyAt(i), packageName); + if (curOp.time == 0 && curOp.rejectTime == 0) { + pkgOps.removeAt(j); + } } } + if (pkgOps.size() == 0) { + it.remove(); + } + } + if (packages.size() == 0) { + mUidOps.removeAt(i); } } if (changed) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3ae2eb5..bb0d248 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2221,15 +2221,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info); thisNet.captivePortalCheckComplete(); } /** @hide */ + @Override public void captivePortalCheckComplete(NetworkInfo info) { enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckComplete: ni=" + info); mNetTrackers[info.getType()].captivePortalCheckComplete(); } + /** @hide */ + @Override + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal); + mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); + } + /** * Setup data activity tracking for the given network interface. * @@ -3916,11 +3927,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI, new Binder()); // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + + // First wait until we can start using hipri + Binder binder = new Binder(); + while(SystemClock.elapsedRealtime() < endTime) { + int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI, binder); + if ((ret == PhoneConstants.APN_ALREADY_ACTIVE) + || (ret == PhoneConstants.APN_REQUEST_STARTED)) { + log("isMobileOk: hipri started"); + break; + } + if (VDBG) log("isMobileOk: hipri not started yet"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + sleep(1); + } + + // Continue trying to connect until time has run out while(SystemClock.elapsedRealtime() < endTime) { try { // Wait for hipri to connect. @@ -4272,7 +4298,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { return null; } - private String getMobileRedirectedProvisioningUrl() { + @Override + public String getMobileRedirectedProvisioningUrl() { + enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); @@ -4280,14 +4308,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override public String getMobileProvisioningUrl() { enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); } else { - log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url); } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 4c81006..43f95c3 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -2378,7 +2378,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public boolean setDeviceOwner(String packageName) { + public boolean setDeviceOwner(String packageName, String ownerName) { if (packageName == null || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) { throw new IllegalArgumentException("Invalid package name " + packageName @@ -2386,7 +2386,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } synchronized (this) { if (mDeviceOwner == null && !isDeviceProvisioned()) { - mDeviceOwner = new DeviceOwner(packageName); + mDeviceOwner = new DeviceOwner(packageName, ownerName); mDeviceOwner.writeOwnerFile(); return true; } else { @@ -2415,6 +2415,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } + @Override + public String getDeviceOwnerName() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); + synchronized (this) { + if (mDeviceOwner != null) { + return mDeviceOwner.getName(); + } + } + return null; + } + private boolean isDeviceProvisioned() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) > 0; @@ -2488,15 +2499,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { static class DeviceOwner { private static final String DEVICE_OWNER_XML = "device_owner.xml"; private static final String TAG_DEVICE_OWNER = "device-owner"; + private static final String ATTR_NAME = "name"; private static final String ATTR_PACKAGE = "package"; private String mPackageName; + private String mOwnerName; DeviceOwner() { readOwnerFile(); } - DeviceOwner(String packageName) { + DeviceOwner(String packageName, String ownerName) { this.mPackageName = packageName; + this.mOwnerName = ownerName; } static boolean isRegistered() { @@ -2508,6 +2522,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mPackageName; } + String getName() { + return mOwnerName; + } + static boolean isInstalled(String packageName, PackageManager pm) { try { PackageInfo pi; @@ -2539,6 +2557,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Device Owner file does not start with device-owner tag: found " + tag); } mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE); + mOwnerName = parser.getAttributeValue(null, ATTR_NAME); input.close(); } catch (XmlPullParserException xppe) { Slog.e(TAG, "Error parsing device-owner file\n" + xppe); @@ -2563,6 +2582,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.startDocument(null, true); out.startTag(null, TAG_DEVICE_OWNER); out.attribute(null, ATTR_PACKAGE, mPackageName); + if (mOwnerName != null) { + out.attribute(null, ATTR_NAME, mOwnerName); + } out.endTag(null, TAG_DEVICE_OWNER); out.endDocument(); out.flush(); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index cde84dc..49746ff 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -63,6 +63,8 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.internal.os.BackgroundThread; +import com.android.server.location.FlpHardwareProvider; +import com.android.server.location.FusedProxy; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceProxy; import com.android.server.location.GeofenceManager; @@ -429,6 +431,17 @@ public class LocationManagerService extends ILocationManager.Stub { Slog.e(TAG, "no geofence provider found"); } + // bind to fused provider + // TODO: [GeofenceIntegration] bind #getGeofenceHardware() with the GeofenceProxy + FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext); + FusedProxy fusedProxy = FusedProxy.createAndBind( + mContext, + mLocationHandler, + flpHardwareProvider.getLocationHardware()); + + if(fusedProxy == null) { + Slog.e(TAG, "No FusedProvider found."); + } } /** @@ -552,8 +565,14 @@ public class LocationManagerService extends ILocationManager.Stub { allowHighPower = false; } } + boolean wasHighPowerMonitoring = mOpHighPowerMonitoring; mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring, AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION); + if (mOpHighPowerMonitoring != wasHighPowerMonitoring) { + // send an intent to notify that a high power request has been added/removed. + Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } } /** diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 18b46fb..8fb3998 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -41,6 +41,7 @@ import com.android.internal.R; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** * This class is a strategy for performing touch exploration. It @@ -52,10 +53,8 @@ import java.util.Arrays; * <li>2. One finger moving fast around performs gestures.</li> * <li>3. Two close fingers moving in the same direction perform a drag.</li> * <li>4. Multi-finger gestures are delivered to view hierarchy.</li> - * <li>5. Pointers that have not moved more than a specified distance after they - * went down are considered inactive.</li> - * <li>6. Two fingers moving in different directions are considered a multi-finger gesture.</li> - * <li>7. Double tapping clicks on the on the last touch explored location of it was in + * <li>5. Two fingers moving in different directions are considered a multi-finger gesture.</li> + * <li>7. Double tapping clicks on the on the last touch explored location if it was in * a window that does not take focus, otherwise the click is within the accessibility * focused rectangle.</li> * <li>7. Tapping and holding for a while performs a long press in a similar fashion @@ -102,9 +101,6 @@ class TouchExplorer implements EventStreamTransformation { // The timeout after which we are no longer trying to detect a gesture. private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000; - // Temporary array for storing pointer IDs. - private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT]; - // Timeout before trying to decide what the user is trying to do. private final int mDetermineUserIntentTimeout; @@ -129,11 +125,11 @@ class TouchExplorer implements EventStreamTransformation { // Handler for performing asynchronous operations. private final Handler mHandler; - // Command for delayed sending of a hover enter event. - private final SendHoverDelayed mSendHoverEnterDelayed; + // Command for delayed sending of a hover enter and move event. + private final SendHoverEnterAndMoveDelayed mSendHoverEnterAndMoveDelayed; // Command for delayed sending of a hover exit event. - private final SendHoverDelayed mSendHoverExitDelayed; + private final SendHoverExitDelayed mSendHoverExitDelayed; // Command for delayed sending of touch exploration end events. private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed; @@ -220,7 +216,7 @@ class TouchExplorer implements EventStreamTransformation { public TouchExplorer(Context context, AccessibilityManagerService service) { mContext = context; mAms = service; - mReceivedPointerTracker = new ReceivedPointerTracker(context); + mReceivedPointerTracker = new ReceivedPointerTracker(); mInjectedPointerTracker = new InjectedPointerTracker(); mTapTimeout = ViewConfiguration.getTapTimeout(); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); @@ -234,8 +230,8 @@ class TouchExplorer implements EventStreamTransformation { mGestureLibrary.setOrientationStyle(8); mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE); mGestureLibrary.load(); - mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true); - mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false); + mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed(); + mSendHoverExitDelayed = new SendHoverExitDelayed(); mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed( AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END, mDetermineUserIntentTimeout); @@ -283,12 +279,12 @@ class TouchExplorer implements EventStreamTransformation { } break; } // Remove all pending callbacks. - mSendHoverEnterDelayed.remove(); - mSendHoverExitDelayed.remove(); - mPerformLongPressDelayed.remove(); - mExitGestureDetectionModeDelayed.remove(); - mSendTouchExplorationEndDelayed.remove(); - mSendTouchInteractionEndDelayed.remove(); + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); + mExitGestureDetectionModeDelayed.cancel(); + mSendTouchExplorationEndDelayed.cancel(); + mSendTouchInteractionEndDelayed.cancel(); // Reset the pointer trackers. mReceivedPointerTracker.clear(); mInjectedPointerTracker.clear(); @@ -347,7 +343,7 @@ class TouchExplorer implements EventStreamTransformation { // last hover exit event. if (mSendTouchExplorationEndDelayed.isPending() && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { - mSendTouchExplorationEndDelayed.remove(); + mSendTouchExplorationEndDelayed.cancel(); sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END); } @@ -355,7 +351,7 @@ class TouchExplorer implements EventStreamTransformation { // last hover exit and the touch exploration gesture end events. if (mSendTouchInteractionEndDelayed.isPending() && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { - mSendTouchInteractionEndDelayed.remove(); + mSendTouchInteractionEndDelayed.cancel(); sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); } @@ -390,95 +386,80 @@ class TouchExplorer implements EventStreamTransformation { private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent rawEvent, int policyFlags) { ReceivedPointerTracker receivedTracker = mReceivedPointerTracker; - final int activePointerCount = receivedTracker.getActivePointerCount(); mVelocityTracker.addMovement(rawEvent); mDoubleTapDetector.onMotionEvent(event, policyFlags); switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_DOWN: { mAms.onTouchInteractionStart(); + // Pre-feed the motion events to the gesture detector since we // have a distance slop before getting into gesture detection // mode and not using the points within this slop significantly // decreases the quality of gesture recognition. handleMotionEventGestureDetecting(rawEvent, policyFlags); - //$FALL-THROUGH$ - case MotionEvent.ACTION_POINTER_DOWN: { - switch (activePointerCount) { - case 0: { - throw new IllegalStateException("The must always be one active pointer in" - + "touch exploring state!"); - } - case 1: { - // If we still have not notified the user for the last - // touch, we figure out what to do. If were waiting - // we resent the delayed callback and wait again. - if (mSendHoverEnterDelayed.isPending()) { - mSendHoverEnterDelayed.remove(); - mSendHoverExitDelayed.remove(); - } + sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START); - if (mSendTouchExplorationEndDelayed.isPending()) { - mSendTouchExplorationEndDelayed.forceSendAndRemove(); - } + // If we still have not notified the user for the last + // touch, we figure out what to do. If were waiting + // we resent the delayed callback and wait again. + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); - if (mSendTouchInteractionEndDelayed.isPending()) { - mSendTouchInteractionEndDelayed.forceSendAndRemove(); - } + if (mSendTouchExplorationEndDelayed.isPending()) { + mSendTouchExplorationEndDelayed.forceSendAndRemove(); + } - // Every pointer that goes down is active until it moves or - // another one goes down. Hence, having more than one pointer - // down we have already send the interaction start event. - if (event.getPointerCount() == 1) { - sendAccessibilityEvent( - AccessibilityEvent.TYPE_TOUCH_INTERACTION_START); - } + if (mSendTouchInteractionEndDelayed.isPending()) { + mSendTouchInteractionEndDelayed.forceSendAndRemove(); + } - mPerformLongPressDelayed.remove(); - - // If we have the first tap schedule a long press and break - // since we do not want to schedule hover enter because - // the delayed callback will kick in before the long click. - // This would lead to a state transition resulting in long - // pressing the item below the double taped area which is - // not necessary where accessibility focus is. - if (mDoubleTapDetector.firstTapDetected()) { - // We got a tap now post a long press action. - mPerformLongPressDelayed.post(event, policyFlags); - break; - } - if (!mTouchExplorationInProgress) { - // Deliver hover enter with a delay to have a chance - // to detect what the user is trying to do. - final int pointerId = receivedTracker.getPrimaryActivePointerId(); - final int pointerIdBits = (1 << pointerId); - mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags); - } - } break; - default: { - /* do nothing - let the code for ACTION_MOVE decide what to do */ - } break; + // Cache the event until we discern exploration from gesturing. + mSendHoverEnterAndMoveDelayed.addEvent(event); + + // If we have the first tap, schedule a long press and break + // since we do not want to schedule hover enter because + // the delayed callback will kick in before the long click. + // This would lead to a state transition resulting in long + // pressing the item below the double taped area which is + // not necessary where accessibility focus is. + if (mDoubleTapDetector.firstTapDetected()) { + // We got a tap now post a long press action. + mPerformLongPressDelayed.post(event, policyFlags); + break; } + if (!mTouchExplorationInProgress) { + // Deliver hover enter with a delay to have a chance + // to detect what the user is trying to do. + final int pointerId = receivedTracker.getPrimaryPointerId(); + final int pointerIdBits = (1 << pointerId); + mSendHoverEnterAndMoveDelayed.post(event, true, pointerIdBits, policyFlags); + } + } break; + case MotionEvent.ACTION_POINTER_DOWN: { + /* do nothing - let the code for ACTION_MOVE decide what to do */ } break; case MotionEvent.ACTION_MOVE: { - final int pointerId = receivedTracker.getPrimaryActivePointerId(); + final int pointerId = receivedTracker.getPrimaryPointerId(); final int pointerIndex = event.findPointerIndex(pointerId); final int pointerIdBits = (1 << pointerId); - switch (activePointerCount) { - case 0: { - /* do nothing - no active pointers so we swallow the event */ - } break; + switch (event.getPointerCount()) { case 1: { // We have not started sending events since we try to // figure out what the user is doing. - if (mSendHoverEnterDelayed.isPending()) { + if (mSendHoverEnterAndMoveDelayed.isPending()) { // Pre-feed the motion events to the gesture detector since we // have a distance slop before getting into gesture detection // mode and not using the points within this slop significantly // decreases the quality of gesture recognition. handleMotionEventGestureDetecting(rawEvent, policyFlags); + + // Cache the event until we discern exploration from gesturing. + mSendHoverEnterAndMoveDelayed.addEvent(event); + // It is *important* to use the distance traveled by the pointers // on the screen which may or may not be magnified. final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId) @@ -500,9 +481,9 @@ class TouchExplorer implements EventStreamTransformation { // clear the current state and try to detect. mCurrentState = STATE_GESTURE_DETECTING; mVelocityTracker.clear(); - mSendHoverEnterDelayed.remove(); - mSendHoverExitDelayed.remove(); - mPerformLongPressDelayed.remove(); + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); mExitGestureDetectionModeDelayed.post(); // Send accessibility event to announce the start // of gesture recognition. @@ -511,9 +492,9 @@ class TouchExplorer implements EventStreamTransformation { } else { // We have just decided that the user is touch, // exploring so start sending events. - mSendHoverEnterDelayed.forceSendAndRemove(); - mSendHoverExitDelayed.remove(); - mPerformLongPressDelayed.remove(); + mSendHoverEnterAndMoveDelayed.forceSendAndRemove(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags); } @@ -532,11 +513,11 @@ class TouchExplorer implements EventStreamTransformation { final double moveDelta = Math.hypot(deltaX, deltaY); // The user has moved enough for us to decide. if (moveDelta > mTouchSlop) { - mPerformLongPressDelayed.remove(); + mPerformLongPressDelayed.cancel(); } } - // The user is wither double tapping or performing long - // press so do not send move events yet. + // The user is either double tapping or performing a long + // press, so do not send move events yet. if (mDoubleTapDetector.firstTapDetected()) { break; } @@ -548,14 +529,14 @@ class TouchExplorer implements EventStreamTransformation { case 2: { // More than one pointer so the user is not touch exploring // and now we have to decide whether to delegate or drag. - if (mSendHoverEnterDelayed.isPending()) { + if (mSendHoverEnterAndMoveDelayed.isPending()) { // We have not started sending events so cancel // scheduled sending events. - mSendHoverEnterDelayed.remove(); - mSendHoverExitDelayed.remove(); - mPerformLongPressDelayed.remove(); + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); } else { - mPerformLongPressDelayed.remove(); + mPerformLongPressDelayed.cancel(); // If the user is touch exploring the second pointer may be // performing a double tap to activate an item without need // for the user to lift his exploring finger. @@ -590,21 +571,21 @@ class TouchExplorer implements EventStreamTransformation { } else { // Two pointers moving arbitrary are delegated to the view hierarchy. mCurrentState = STATE_DELEGATING; - sendDownForAllActiveNotInjectedPointers(event, policyFlags); + sendDownForAllNotInjectedPointers(event, policyFlags); } mVelocityTracker.clear(); } break; default: { // More than one pointer so the user is not touch exploring // and now we have to decide whether to delegate or drag. - if (mSendHoverEnterDelayed.isPending()) { + if (mSendHoverEnterAndMoveDelayed.isPending()) { // We have not started sending events so cancel // scheduled sending events. - mSendHoverEnterDelayed.remove(); - mSendHoverExitDelayed.remove(); - mPerformLongPressDelayed.remove(); + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); } else { - mPerformLongPressDelayed.remove(); + mPerformLongPressDelayed.cancel(); // We are sending events so send exit and gesture // end since we transition to another state. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); @@ -612,43 +593,34 @@ class TouchExplorer implements EventStreamTransformation { // More than two pointers are delegated to the view hierarchy. mCurrentState = STATE_DELEGATING; - sendDownForAllActiveNotInjectedPointers(event, policyFlags); + sendDownForAllNotInjectedPointers(event, policyFlags); mVelocityTracker.clear(); } } } break; - case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_UP: { mAms.onTouchInteractionEnd(); // We know that we do not need the pre-fed gesture points are not // needed anymore since the last pointer just went up. mStrokeBuffer.clear(); - //$FALL-THROUGH$ - case MotionEvent.ACTION_POINTER_UP: { - final int pointerId = receivedTracker.getLastReceivedUpPointerId(); + final int pointerId = event.getPointerId(event.getActionIndex()); final int pointerIdBits = (1 << pointerId); - switch (activePointerCount) { - case 0: { - // If the pointer that went up was not active we have nothing to do. - if (!receivedTracker.wasLastReceivedUpPointerActive()) { - break; - } - mPerformLongPressDelayed.remove(); + mPerformLongPressDelayed.cancel(); + mVelocityTracker.clear(); - // If we have not delivered the enter schedule exit. - if (mSendHoverEnterDelayed.isPending()) { - mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags); - } else { - // The user is touch exploring so we send events for end. - sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); - } + if (mSendHoverEnterAndMoveDelayed.isPending()) { + // If we have not delivered the enter schedule an exit. + mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags); + } else { + // The user is touch exploring so we send events for end. + sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); + } - if (!mSendTouchInteractionEndDelayed.isPending()) { - mSendTouchInteractionEndDelayed.post(); - } - } break; + if (!mSendTouchInteractionEndDelayed.isPending()) { + mSendTouchInteractionEndDelayed.post(); } - mVelocityTracker.clear(); + } break; case MotionEvent.ACTION_CANCEL: { clear(event, policyFlags); @@ -676,29 +648,19 @@ class TouchExplorer implements EventStreamTransformation { if (mDraggingPointerId != INVALID_POINTER_ID) { sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); } - sendDownForAllActiveNotInjectedPointers(event, policyFlags); + sendDownForAllNotInjectedPointers(event, policyFlags); } break; case MotionEvent.ACTION_MOVE: { - final int activePointerCount = mReceivedPointerTracker.getActivePointerCount(); - switch (activePointerCount) { + switch (event.getPointerCount()) { case 1: { // do nothing } break; case 2: { if (isDraggingGesture(event)) { - // If the dragging pointer are closer that a given distance we - // use the location of the primary one. Otherwise, we take the - // middle between the pointers. - int[] pointerIds = mTempPointerIds; - mReceivedPointerTracker.populateActivePointerIds(pointerIds); - - final int firstPtrIndex = event.findPointerIndex(pointerIds[0]); - final int secondPtrIndex = event.findPointerIndex(pointerIds[1]); - - final float firstPtrX = event.getX(firstPtrIndex); - final float firstPtrY = event.getY(firstPtrIndex); - final float secondPtrX = event.getX(secondPtrIndex); - final float secondPtrY = event.getY(secondPtrIndex); + final float firstPtrX = event.getX(0); + final float firstPtrY = event.getY(0); + final float secondPtrX = event.getX(1); + final float secondPtrY = event.getY(1); final float deltaX = firstPtrX - secondPtrX; final float deltaY = firstPtrY - secondPtrY; @@ -718,8 +680,8 @@ class TouchExplorer implements EventStreamTransformation { // Send an event to the end of the drag gesture. sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); - // Deliver all active pointers to the view hierarchy. - sendDownForAllActiveNotInjectedPointers(event, policyFlags); + // Deliver all pointers to the view hierarchy. + sendDownForAllNotInjectedPointers(event, policyFlags); } } break; default: { @@ -727,8 +689,8 @@ class TouchExplorer implements EventStreamTransformation { // Send an event to the end of the drag gesture. sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); - // Deliver all active pointers to the view hierarchy. - sendDownForAllActiveNotInjectedPointers(event, policyFlags); + // Deliver all pointers to the view hierarchy. + sendDownForAllNotInjectedPointers(event, policyFlags); } } } break; @@ -771,37 +733,21 @@ class TouchExplorer implements EventStreamTransformation { throw new IllegalStateException("Delegating state can only be reached if " + "there is at least one pointer down!"); } - case MotionEvent.ACTION_MOVE: { - // Check whether some other pointer became active because they have moved - // a given distance and if such exist send them to the view hierarchy - final int notInjectedCount = getNotInjectedActivePointerCount( - mReceivedPointerTracker, mInjectedPointerTracker); - if (notInjectedCount > 0) { - MotionEvent prototype = MotionEvent.obtain(event); - sendDownForAllActiveNotInjectedPointers(prototype, policyFlags); - } - } break; - case MotionEvent.ACTION_UP: - // Announce the end of a new touch interaction. - sendAccessibilityEvent( - AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); - //$FALL-THROUGH$ - case MotionEvent.ACTION_POINTER_UP: { + case MotionEvent.ACTION_UP: { + // Announce the end of a the touch interaction. + sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); mAms.onTouchInteractionEnd(); mLongPressingPointerId = -1; mLongPressingPointerDeltaX = 0; mLongPressingPointerDeltaY = 0; - // No active pointers => go to initial state. - if (mReceivedPointerTracker.getActivePointerCount() == 0) { - mCurrentState = STATE_TOUCH_EXPLORING; - } + mCurrentState = STATE_TOUCH_EXPLORING; } break; case MotionEvent.ACTION_CANCEL: { clear(event, policyFlags); } break; } - // Deliver the event striping out inactive pointers. - sendMotionEventStripInactivePointers(event, policyFlags); + // Deliver the event. + sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); } private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) { @@ -826,12 +772,10 @@ class TouchExplorer implements EventStreamTransformation { } break; case MotionEvent.ACTION_UP: { mAms.onTouchInteractionEnd(); - // Announce the end of gesture recognition. - sendAccessibilityEvent( - AccessibilityEvent.TYPE_GESTURE_DETECTION_END); - // Announce the end of a new touch interaction. - sendAccessibilityEvent( - AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); + // Announce the end of the gesture recognition. + sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END); + // Announce the end of a the touch interaction. + sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); float x = event.getX(); float y = event.getY(); @@ -858,7 +802,7 @@ class TouchExplorer implements EventStreamTransformation { } mStrokeBuffer.clear(); - mExitGestureDetectionModeDelayed.remove(); + mExitGestureDetectionModeDelayed.cancel(); mCurrentState = STATE_TOUCH_EXPLORING; } break; case MotionEvent.ACTION_CANCEL: { @@ -889,40 +833,26 @@ class TouchExplorer implements EventStreamTransformation { } /** - * Sends down events to the view hierarchy for all active pointers which are + * Sends down events to the view hierarchy for all pointers which are * not already being delivered i.e. pointers that are not yet injected. * * @param prototype The prototype from which to create the injected events. * @param policyFlags The policy flags associated with the event. */ - private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) { - ReceivedPointerTracker receivedPointers = mReceivedPointerTracker; + private void sendDownForAllNotInjectedPointers(MotionEvent prototype, int policyFlags) { InjectedPointerTracker injectedPointers = mInjectedPointerTracker; + + // Inject the injected pointers. int pointerIdBits = 0; final int pointerCount = prototype.getPointerCount(); - - // Find which pointers are already injected. - for (int i = 0; i < pointerCount; i++) { - final int pointerId = prototype.getPointerId(i); - if (injectedPointers.isInjectedPointerDown(pointerId)) { - pointerIdBits |= (1 << pointerId); - } - } - - // Inject the active and not injected pointers. for (int i = 0; i < pointerCount; i++) { final int pointerId = prototype.getPointerId(i); - // Skip inactive pointers. - if (!receivedPointers.isActivePointer(pointerId)) { - continue; - } // Do not send event for already delivered pointers. - if (injectedPointers.isInjectedPointerDown(pointerId)) { - continue; + if (!injectedPointers.isInjectedPointerDown(pointerId)) { + pointerIdBits |= (1 << pointerId); + final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); + sendMotionEvent(prototype, action, pointerIdBits, policyFlags); } - pointerIdBits |= (1 << pointerId); - final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); - sendMotionEvent(prototype, action, pointerIdBits, policyFlags); } } @@ -959,7 +889,7 @@ class TouchExplorer implements EventStreamTransformation { } /** - * Sends up events to the view hierarchy for all active pointers which are + * Sends up events to the view hierarchy for all pointers which are * already being delivered i.e. pointers that are injected. * * @param prototype The prototype from which to create the injected events. @@ -982,58 +912,13 @@ class TouchExplorer implements EventStreamTransformation { } /** - * Sends a motion event by first stripping the inactive pointers. - * - * @param prototype The prototype from which to create the injected event. - * @param policyFlags The policy flags associated with the event. - */ - private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) { - ReceivedPointerTracker receivedTracker = mReceivedPointerTracker; - - // All pointers active therefore we just inject the event as is. - if (prototype.getPointerCount() == receivedTracker.getActivePointerCount()) { - sendMotionEvent(prototype, prototype.getAction(), ALL_POINTER_ID_BITS, policyFlags); - return; - } - - // No active pointers and the one that just went up was not - // active, therefore we have nothing to do. - if (receivedTracker.getActivePointerCount() == 0 - && !receivedTracker.wasLastReceivedUpPointerActive()) { - return; - } - - // If the action pointer going up/down is not active we have nothing to do. - // However, for moves we keep going to report moves of active pointers. - final int actionMasked = prototype.getActionMasked(); - final int actionPointerId = prototype.getPointerId(prototype.getActionIndex()); - if (actionMasked != MotionEvent.ACTION_MOVE) { - if (!receivedTracker.isActiveOrWasLastActiveUpPointer(actionPointerId)) { - return; - } - } - - // If the pointer is active or the pointer that just went up - // was active we keep the pointer data in the event. - int pointerIdBits = 0; - final int pointerCount = prototype.getPointerCount(); - for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) { - final int pointerId = prototype.getPointerId(pointerIndex); - if (receivedTracker.isActiveOrWasLastActiveUpPointer(pointerId)) { - pointerIdBits |= (1 << pointerId); - } - } - sendMotionEvent(prototype, prototype.getAction(), pointerIdBits, policyFlags); - } - - /** * Sends an up and down events. * * @param prototype The prototype from which to create the injected events. * @param policyFlags The policy flags associated with the event. */ private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) { - // Tap with the pointer that last explored - we may have inactive pointers. + // Tap with the pointer that last explored. final int pointerId = prototype.getPointerId(prototype.getActionIndex()); final int pointerIdBits = (1 << pointerId); sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags); @@ -1215,9 +1100,9 @@ class TouchExplorer implements EventStreamTransformation { } // Remove pending event deliveries. - mSendHoverEnterDelayed.remove(); - mSendHoverExitDelayed.remove(); - mPerformLongPressDelayed.remove(); + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); if (mSendTouchExplorationEndDelayed.isPending()) { mSendTouchExplorationEndDelayed.forceSendAndRemove(); @@ -1307,21 +1192,16 @@ class TouchExplorer implements EventStreamTransformation { */ private boolean isDraggingGesture(MotionEvent event) { ReceivedPointerTracker receivedTracker = mReceivedPointerTracker; - int[] pointerIds = mTempPointerIds; - receivedTracker.populateActivePointerIds(pointerIds); - - final int firstPtrIndex = event.findPointerIndex(pointerIds[0]); - final int secondPtrIndex = event.findPointerIndex(pointerIds[1]); - final float firstPtrX = event.getX(firstPtrIndex); - final float firstPtrY = event.getY(firstPtrIndex); - final float secondPtrX = event.getX(secondPtrIndex); - final float secondPtrY = event.getY(secondPtrIndex); + final float firstPtrX = event.getX(0); + final float firstPtrY = event.getY(0); + final float secondPtrX = event.getX(1); + final float secondPtrY = event.getY(1); - final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(firstPtrIndex); - final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(firstPtrIndex); - final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(secondPtrIndex); - final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(secondPtrIndex); + final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(0); + final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(0); + final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(1); + final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(1); return GestureUtils.isDraggingGesture(firstPtrDownX, firstPtrDownY, secondPtrDownX, secondPtrDownY, firstPtrX, firstPtrY, secondPtrX, secondPtrY, @@ -1350,16 +1230,6 @@ class TouchExplorer implements EventStreamTransformation { } /** - * @return The number of non injected active pointers. - */ - private int getNotInjectedActivePointerCount(ReceivedPointerTracker receivedTracker, - InjectedPointerTracker injectedTracker) { - final int pointerState = receivedTracker.getActivePointers() - & ~injectedTracker.getInjectedPointersDown(); - return Integer.bitCount(pointerState); - } - - /** * Class for delayed exiting from gesture detecting mode. */ private final class ExitGestureDetectionModeDelayed implements Runnable { @@ -1368,7 +1238,7 @@ class TouchExplorer implements EventStreamTransformation { mHandler.postDelayed(this, EXIT_GESTURE_DETECTION_TIMEOUT); } - public void remove() { + public void cancel() { mHandler.removeCallbacks(this); } @@ -1396,21 +1266,21 @@ class TouchExplorer implements EventStreamTransformation { mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout()); } - public void remove() { - if (isPending()) { + public void cancel() { + if (mEvent != null) { mHandler.removeCallbacks(this); clear(); } } - public boolean isPending() { - return (mEvent != null); + private boolean isPending() { + return mHandler.hasCallbacks(this); } @Override public void run() { - // Active pointers should not be zero when running this command. - if (mReceivedPointerTracker.getActivePointerCount() == 0) { + // Pointers should not be zero when running this command. + if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) { return; } @@ -1461,14 +1331,11 @@ class TouchExplorer implements EventStreamTransformation { sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags); mCurrentState = STATE_DELEGATING; - sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags); + sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags); clear(); } private void clear() { - if (!isPending()) { - return; - } mEvent.recycle(); mEvent = null; mPolicyFlags = 0; @@ -1476,59 +1343,114 @@ class TouchExplorer implements EventStreamTransformation { } /** - * Class for delayed sending of hover events. + * Class for delayed sending of hover enter and move events. */ - class SendHoverDelayed implements Runnable { - private final String LOG_TAG_SEND_HOVER_DELAYED = SendHoverDelayed.class.getName(); + class SendHoverEnterAndMoveDelayed implements Runnable { + private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed"; - private final int mHoverAction; - private final boolean mGestureStarted; + private final List<MotionEvent> mEvents = new ArrayList<MotionEvent>(); - private MotionEvent mPrototype; private int mPointerIdBits; private int mPolicyFlags; - public SendHoverDelayed(int hoverAction, boolean gestureStarted) { - mHoverAction = hoverAction; - mGestureStarted = gestureStarted; - } - - public void post(MotionEvent prototype, boolean touchExplorationInProgress, + public void post(MotionEvent event, boolean touchExplorationInProgress, int pointerIdBits, int policyFlags) { - remove(); - mPrototype = MotionEvent.obtain(prototype); + cancel(); + addEvent(event); mPointerIdBits = pointerIdBits; mPolicyFlags = policyFlags; mHandler.postDelayed(this, mDetermineUserIntentTimeout); } - public float getX() { + public void addEvent(MotionEvent event) { + mEvents.add(MotionEvent.obtain(event)); + } + + public void cancel() { if (isPending()) { - return mPrototype.getX(); + mHandler.removeCallbacks(this); + clear(); + } + } + + private boolean isPending() { + return mHandler.hasCallbacks(this); + } + + private void clear() { + mPointerIdBits = -1; + mPolicyFlags = 0; + final int eventCount = mEvents.size(); + for (int i = eventCount - 1; i >= 0; i--) { + mEvents.remove(i).recycle(); } - return 0; } - public float getY() { + public void forceSendAndRemove() { if (isPending()) { - return mPrototype.getY(); + run(); + cancel(); } - return 0; } - public void remove() { - mHandler.removeCallbacks(this); + public void run() { + // Send an accessibility event to announce the touch exploration start. + sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START); + + if (!mEvents.isEmpty()) { + // Deliver a down event. + sendMotionEvent(mEvents.get(0), MotionEvent.ACTION_HOVER_ENTER, + mPointerIdBits, mPolicyFlags); + if (DEBUG) { + Slog.d(LOG_TAG_SEND_HOVER_DELAYED, + "Injecting motion event: ACTION_HOVER_ENTER"); + } + + // Deliver move events. + final int eventCount = mEvents.size(); + for (int i = 1; i < eventCount; i++) { + sendMotionEvent(mEvents.get(i), MotionEvent.ACTION_HOVER_MOVE, + mPointerIdBits, mPolicyFlags); + if (DEBUG) { + Slog.d(LOG_TAG_SEND_HOVER_DELAYED, + "Injecting motion event: ACTION_HOVER_MOVE"); + } + } + } clear(); } + } + + /** + * Class for delayed sending of hover exit events. + */ + class SendHoverExitDelayed implements Runnable { + private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed"; + + private MotionEvent mPrototype; + private int mPointerIdBits; + private int mPolicyFlags; + + public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) { + cancel(); + mPrototype = MotionEvent.obtain(prototype); + mPointerIdBits = pointerIdBits; + mPolicyFlags = policyFlags; + mHandler.postDelayed(this, mDetermineUserIntentTimeout); + } + + public void cancel() { + if (isPending()) { + mHandler.removeCallbacks(this); + clear(); + } + } private boolean isPending() { - return (mPrototype != null); + return mHandler.hasCallbacks(this); } private void clear() { - if (!isPending()) { - return; - } mPrototype.recycle(); mPrototype = null; mPointerIdBits = -1; @@ -1538,29 +1460,25 @@ class TouchExplorer implements EventStreamTransformation { public void forceSendAndRemove() { if (isPending()) { run(); - remove(); + cancel(); } } public void run() { if (DEBUG) { - Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event: " - + MotionEvent.actionToString(mHoverAction)); - Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ? - "touchExplorationGestureStarted" : "touchExplorationGestureEnded"); + Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:" + + " ACTION_HOVER_EXIT"); } - if (mGestureStarted) { - sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START); - } else { - if (!mSendTouchExplorationEndDelayed.isPending()) { - mSendTouchExplorationEndDelayed.post(); - } - if (mSendTouchInteractionEndDelayed.isPending()) { - mSendTouchInteractionEndDelayed.remove(); - mSendTouchInteractionEndDelayed.post(); - } + sendMotionEvent(mPrototype, MotionEvent.ACTION_HOVER_EXIT, + mPointerIdBits, mPolicyFlags); + if (!mSendTouchExplorationEndDelayed.isPending()) { + mSendTouchExplorationEndDelayed.cancel(); + mSendTouchExplorationEndDelayed.post(); + } + if (mSendTouchInteractionEndDelayed.isPending()) { + mSendTouchInteractionEndDelayed.cancel(); + mSendTouchInteractionEndDelayed.post(); } - sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags); clear(); } } @@ -1574,7 +1492,7 @@ class TouchExplorer implements EventStreamTransformation { mDelay = delay; } - public void remove() { + public void cancel() { mHandler.removeCallbacks(this); } @@ -1589,7 +1507,7 @@ class TouchExplorer implements EventStreamTransformation { public void forceSendAndRemove() { if (isPending()) { run(); - remove(); + cancel(); } } @@ -1736,15 +1654,6 @@ class TouchExplorer implements EventStreamTransformation { class ReceivedPointerTracker { private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker"; - // The coefficient by which to multiply - // ViewConfiguration.#getScaledTouchSlop() - // to compute #mThresholdActivePointer. - private static final int COEFFICIENT_ACTIVE_POINTER = 2; - - // Pointers that moved less than mThresholdActivePointer - // are considered active i.e. are ignored. - private final double mThresholdActivePointer; - // Keep track of where and when a pointer went down. private final float[] mReceivedPointerDownX = new float[MAX_POINTER_COUNT]; private final float[] mReceivedPointerDownY = new float[MAX_POINTER_COUNT]; @@ -1756,36 +1665,19 @@ class TouchExplorer implements EventStreamTransformation { // The edge flags of the last received down event. private int mLastReceivedDownEdgeFlags; - // Which down pointers are active. - private int mActivePointers; - - // Primary active pointer which is either the first that went down - // or if it goes up the next active that most recently went down. - private int mPrimaryActivePointerId; - - // Flag indicating that there is at least one active pointer moving. - private boolean mHasMovingActivePointer; + // Primary pointer which is either the first that went down + // or if it goes up the next one that most recently went down. + private int mPrimaryPointerId; // Keep track of the last up pointer data. private long mLastReceivedUpPointerDownTime; private int mLastReceivedUpPointerId; - private boolean mLastReceivedUpPointerActive; private float mLastReceivedUpPointerDownX; private float mLastReceivedUpPointerDownY; private MotionEvent mLastReceivedEvent; /** - * Creates a new instance. - * - * @param context Context for looking up resources. - */ - public ReceivedPointerTracker(Context context) { - mThresholdActivePointer = - ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER; - } - - /** * Clears the internals state. */ public void clear() { @@ -1793,12 +1685,9 @@ class TouchExplorer implements EventStreamTransformation { Arrays.fill(mReceivedPointerDownY, 0); Arrays.fill(mReceivedPointerDownTime, 0); mReceivedPointersDown = 0; - mActivePointers = 0; - mPrimaryActivePointerId = 0; - mHasMovingActivePointer = false; + mPrimaryPointerId = 0; mLastReceivedUpPointerDownTime = 0; mLastReceivedUpPointerId = 0; - mLastReceivedUpPointerActive = false; mLastReceivedUpPointerDownX = 0; mLastReceivedUpPointerDownY = 0; } @@ -1822,9 +1711,6 @@ class TouchExplorer implements EventStreamTransformation { case MotionEvent.ACTION_POINTER_DOWN: { handleReceivedPointerDown(event.getActionIndex(), event); } break; - case MotionEvent.ACTION_MOVE: { - handleReceivedPointerMove(event); - } break; case MotionEvent.ACTION_UP: { handleReceivedPointerUp(event.getActionIndex(), event); } break; @@ -1852,20 +1738,6 @@ class TouchExplorer implements EventStreamTransformation { } /** - * @return The bits of the pointers that are active. - */ - public int getActivePointers() { - return mActivePointers; - } - - /** - * @return The number of down input pointers that are active. - */ - public int getActivePointerCount() { - return Integer.bitCount(mActivePointers); - } - - /** * Whether an received pointer is down. * * @param pointerId The unique pointer id. @@ -1877,17 +1749,6 @@ class TouchExplorer implements EventStreamTransformation { } /** - * Whether an input pointer is active. - * - * @param pointerId The unique pointer id. - * @return True if the pointer is active. - */ - public boolean isActivePointer(int pointerId) { - final int pointerFlag = (1 << pointerId); - return (mActivePointers & pointerFlag) != 0; - } - - /** * @param pointerId The unique pointer id. * @return The X coordinate where the pointer went down. */ @@ -1914,11 +1775,11 @@ class TouchExplorer implements EventStreamTransformation { /** * @return The id of the primary pointer. */ - public int getPrimaryActivePointerId() { - if (mPrimaryActivePointerId == INVALID_POINTER_ID) { - mPrimaryActivePointerId = findPrimaryActivePointer(); + public int getPrimaryPointerId() { + if (mPrimaryPointerId == INVALID_POINTER_ID) { + mPrimaryPointerId = findPrimaryPointer(); } - return mPrimaryActivePointerId; + return mPrimaryPointerId; } /** @@ -1929,14 +1790,6 @@ class TouchExplorer implements EventStreamTransformation { } /** - * @return The id of the last received pointer that went up. - */ - public int getLastReceivedUpPointerId() { - return mLastReceivedUpPointerId; - } - - - /** * @return The down X of the last received pointer that went up. */ public float getLastReceivedUpPointerDownX() { @@ -1958,39 +1811,6 @@ class TouchExplorer implements EventStreamTransformation { } /** - * @return Whether the last received pointer that went up was active. - */ - public boolean wasLastReceivedUpPointerActive() { - return mLastReceivedUpPointerActive; - } - /** - * Populates the active pointer IDs to the given array. - * <p> - * Note: The client is responsible for providing large enough array. - * - * @param outPointerIds The array to which to write the active pointers. - */ - public void populateActivePointerIds(int[] outPointerIds) { - int index = 0; - for (int idBits = mActivePointers; idBits != 0; ) { - final int id = Integer.numberOfTrailingZeros(idBits); - idBits &= ~(1 << id); - outPointerIds[index] = id; - index++; - } - } - - /** - * @param pointerId The unique pointer id. - * @return Whether the pointer is active or was the last active than went up. - */ - public boolean isActiveOrWasLastActiveUpPointer(int pointerId) { - return (isActivePointer(pointerId) - || (mLastReceivedUpPointerId == pointerId - && mLastReceivedUpPointerActive)); - } - - /** * Handles a received pointer down event. * * @param pointerIndex The index of the pointer that has changed. @@ -2002,7 +1822,6 @@ class TouchExplorer implements EventStreamTransformation { mLastReceivedUpPointerId = 0; mLastReceivedUpPointerDownTime = 0; - mLastReceivedUpPointerActive = false; mLastReceivedUpPointerDownX = 0; mLastReceivedUpPointerDownX = 0; @@ -2013,25 +1832,7 @@ class TouchExplorer implements EventStreamTransformation { mReceivedPointerDownY[pointerId] = event.getY(pointerIndex); mReceivedPointerDownTime[pointerId] = event.getEventTime(); - if (!mHasMovingActivePointer) { - // If still no moving active pointers every - // down pointer is the only active one. - mActivePointers = pointerFlag; - mPrimaryActivePointerId = pointerId; - } else { - // If at least one moving active pointer every - // subsequent down pointer is active. - mActivePointers |= pointerFlag; - } - } - - /** - * Handles a received pointer move event. - * - * @param event The event to be handled. - */ - private void handleReceivedPointerMove(MotionEvent event) { - detectActivePointers(event); + mPrimaryPointerId = pointerId; } /** @@ -2046,80 +1847,34 @@ class TouchExplorer implements EventStreamTransformation { mLastReceivedUpPointerId = pointerId; mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId); - mLastReceivedUpPointerActive = isActivePointer(pointerId); mLastReceivedUpPointerDownX = mReceivedPointerDownX[pointerId]; mLastReceivedUpPointerDownY = mReceivedPointerDownY[pointerId]; mReceivedPointersDown &= ~pointerFlag; - mActivePointers &= ~pointerFlag; mReceivedPointerDownX[pointerId] = 0; mReceivedPointerDownY[pointerId] = 0; mReceivedPointerDownTime[pointerId] = 0; - if (mActivePointers == 0) { - mHasMovingActivePointer = false; - } - if (mPrimaryActivePointerId == pointerId) { - mPrimaryActivePointerId = INVALID_POINTER_ID; - } - } - - /** - * Detects the active pointers in an event. - * - * @param event The event to examine. - */ - private void detectActivePointers(MotionEvent event) { - for (int i = 0, count = event.getPointerCount(); i < count; i++) { - final int pointerId = event.getPointerId(i); - if (mHasMovingActivePointer) { - // If already active => nothing to do. - if (isActivePointer(pointerId)) { - continue; - } - } - // Active pointers are ones that moved more than a given threshold. - final float pointerDeltaMove = computePointerDeltaMove(i, event); - if (pointerDeltaMove > mThresholdActivePointer) { - final int pointerFlag = (1 << pointerId); - mActivePointers |= pointerFlag; - mHasMovingActivePointer = true; - } + if (mPrimaryPointerId == pointerId) { + mPrimaryPointerId = INVALID_POINTER_ID; } } /** - * @return The primary active pointer. + * @return The primary pointer. */ - private int findPrimaryActivePointer() { - int primaryActivePointerId = INVALID_POINTER_ID; + private int findPrimaryPointer() { + int primaryPointerId = INVALID_POINTER_ID; long minDownTime = Long.MAX_VALUE; - // Find the active pointer that went down first. + // Find the pointer that went down first. for (int i = 0, count = mReceivedPointerDownTime.length; i < count; i++) { - if (isActivePointer(i)) { - final long downPointerTime = mReceivedPointerDownTime[i]; - if (downPointerTime < minDownTime) { - minDownTime = downPointerTime; - primaryActivePointerId = i; - } + final long downPointerTime = mReceivedPointerDownTime[i]; + if (downPointerTime < minDownTime) { + minDownTime = downPointerTime; + primaryPointerId = i; } } - return primaryActivePointerId; - } - - /** - * Computes the move for a given action pointer index since the - * corresponding pointer went down. - * - * @param pointerIndex The action pointer index. - * @param event The event to examine. - * @return The distance the pointer has moved. - */ - private float computePointerDeltaMove(int pointerIndex, MotionEvent event) { - final int pointerId = event.getPointerId(pointerIndex); - final float deltaX = event.getX(pointerIndex) - mReceivedPointerDownX[pointerId]; - final float deltaY = event.getY(pointerIndex) - mReceivedPointerDownY[pointerId]; - return (float) Math.hypot(deltaX, deltaY); + return primaryPointerId; } @Override @@ -2136,18 +1891,8 @@ class TouchExplorer implements EventStreamTransformation { } } builder.append("]"); - builder.append("\nActive pointers #"); - builder.append(getActivePointerCount()); - builder.append(" [ "); - for (int i = 0; i < MAX_POINTER_COUNT; i++) { - if (isActivePointer(i)) { - builder.append(i); - builder.append(" "); - } - } - builder.append("]"); - builder.append("\nPrimary active pointer id [ "); - builder.append(getPrimaryActivePointerId()); + builder.append("\nPrimary pointer id [ "); + builder.append(getPrimaryPointerId()); builder.append(" ]"); builder.append("\n========================="); return builder.toString(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 3d8843e..9dba2ed 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -42,7 +42,7 @@ import com.android.internal.util.MemInfoReader; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.IntentResolver; -import com.android.server.ProcessMap; +import com.android.internal.app.ProcessMap; import com.android.server.SystemServer; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; @@ -1554,11 +1554,11 @@ public final class ActivityManagerService extends ActivityManagerNative try { ActivityManagerService m = mSelf; - ServiceManager.addService("activity", m, true); + ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true); + ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats); ServiceManager.addService("meminfo", new MemBinder(m)); ServiceManager.addService("gfxinfo", new GraphicsBinder(m)); ServiceManager.addService("dbinfo", new DbBinder(m)); - ServiceManager.addService("procstats", new ProcBinder(m)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(m)); } @@ -1775,26 +1775,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - static class ProcBinder extends Binder { - ActivityManagerService mActivityManagerService; - ProcBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump procstats from from pid=" - + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() - + " without permission " + android.Manifest.permission.DUMP); - return; - } - - mActivityManagerService.mProcessStats.dump(fd, pw, args); - } - } - private ActivityManagerService() { Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); @@ -8453,9 +8433,17 @@ public final class ActivityManagerService extends ActivityManagerNative resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0; boolean alwaysFinishActivities = Settings.Global.getInt( resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0; + boolean forceRtl = Settings.Global.getInt( + resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0; + // Transfer any global setting for forcing RTL layout, into a System Property + SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0"); Configuration configuration = new Configuration(); Settings.System.getConfiguration(resolver, configuration); + if (forceRtl) { + // This will take care of setting the correct layout direction flags + configuration.setLayoutDirection(configuration.locale); + } synchronized (this) { mDebugApp = mOrigDebugApp = debugApp; diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java index 8b4a5a0..6611a24 100644 --- a/services/java/com/android/server/am/ProcessStatsService.java +++ b/services/java/com/android/server/am/ProcessStatsService.java @@ -18,6 +18,8 @@ package com.android.server.am; import android.app.AppGlobals; import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -59,7 +61,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so. static long COMMIT_PERIOD = 24*60*60*1000; // Commit current stats every day. - final Object mLock; + final ActivityManagerService mAm; final File mBaseDir; ProcessStats mProcessStats; AtomicFile mFile; @@ -75,15 +77,15 @@ public final class ProcessStatsService extends IProcessStats.Stub { boolean mPendingWriteCommitted; long mLastWriteTime; - public ProcessStatsService(Object lock, File file) { - mLock = lock; + public ProcessStatsService(ActivityManagerService am, File file) { + mAm = am; mBaseDir = file; mBaseDir.mkdirs(); mProcessStats = new ProcessStats(true); updateFile(); SystemProperties.addChangeCallback(new Runnable() { @Override public void run() { - synchronized (mLock) { + synchronized (mAm) { if (mProcessStats.evaluateSystemProperties(false)) { mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS; writeStateLocked(true, true); @@ -101,17 +103,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid, String processName, String className) { - final ProcessStats.PackageState as = mProcessStats.getPackageStateLocked(packageName, uid); - ProcessStats.ServiceState ss = as.mServices.get(className); - if (ss != null) { - ss.makeActive(); - return ss; - } - final ProcessStats.ProcessState ps = mProcessStats.getProcessStateLocked(packageName, - uid, processName); - ss = new ProcessStats.ServiceState(mProcessStats, packageName, ps); - as.mServices.put(className, ss); - return ss; + return mProcessStats.getServiceStateLocked(packageName, uid, processName, className); } public boolean isMemFactorLowered() { @@ -269,40 +261,11 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } - static byte[] readFully(FileInputStream stream) throws java.io.IOException { - int pos = 0; - int avail = stream.available(); - byte[] data = new byte[avail]; - while (true) { - int amt = stream.read(data, pos, data.length-pos); - //Log.i("foo", "Read " + amt + " bytes at " + pos - // + " of avail " + data.length); - if (amt <= 0) { - //Log.i("foo", "**** FINISHED READING: pos=" + pos - // + " len=" + data.length); - return data; - } - pos += amt; - avail = stream.available(); - if (avail > data.length-pos) { - byte[] newData = new byte[pos+avail]; - System.arraycopy(data, 0, newData, 0, pos); - data = newData; - } - } - } - boolean readLocked(ProcessStats stats, AtomicFile file) { try { FileInputStream stream = file.openRead(); - - byte[] raw = readFully(stream); - Parcel in = Parcel.obtain(); - in.unmarshall(raw, 0, raw.length); - in.setDataPosition(0); + stats.read(stream); stream.close(); - - stats.readFromParcel(in); if (stats.mReadError != null) { Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError); if (DEBUG) { @@ -449,7 +412,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { Parcel current = Parcel.obtain(); mWriteLock.lock(); try { - synchronized (mLock) { + synchronized (mAm) { mProcessStats.writeToParcel(current, 0); } if (historic != null) { @@ -493,7 +456,16 @@ public final class ProcessStatsService extends IProcessStats.Stub { pw.println(" <package.name>: optional name of package to filter output by."); } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mAm.checkCallingPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump procstats from from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " without permission " + android.Manifest.permission.DUMP); + return; + } + final long now = SystemClock.uptimeMillis(); boolean isCheckin = false; @@ -638,7 +610,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } pw.println(); - synchronized (mLock) { + synchronized (mAm) { dumpFilteredProcessesCsvLocked(pw, null, csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats, csvSepProcStats, csvProcStats, now, reqPackage); @@ -721,7 +693,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } if (!isCheckin) { - synchronized (mLock) { + synchronized (mAm) { if (isCompact) { mProcessStats.dumpCheckinLocked(pw, reqPackage); } else { diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index 4b3463c..659163c 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -154,9 +154,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { // List of all currently connected display devices. private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>(); - // List of all removed display devices. - private final ArrayList<DisplayDevice> mRemovedDisplayDevices = new ArrayList<DisplayDevice>(); - // List of all logical displays indexed by logical display id. private final SparseArray<LogicalDisplay> mLogicalDisplays = new SparseArray<LogicalDisplay>(); @@ -798,7 +795,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); - mRemovedDisplayDevices.add(device); updateLogicalDisplaysLocked(); scheduleTraversalLocked(false); } @@ -900,14 +896,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } private void performTraversalInTransactionLocked() { - // Perform one last traversal for each removed display device. - final int removedCount = mRemovedDisplayDevices.size(); - for (int i = 0; i < removedCount; i++) { - DisplayDevice device = mRemovedDisplayDevices.get(i); - device.performTraversalInTransactionLocked(); - } - mRemovedDisplayDevices.clear(); - // Clear all viewports before configuring displays so that we can keep // track of which ones we have configured. clearViewportsLocked(); diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java index ce402a5..007acf7 100644 --- a/services/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java @@ -211,11 +211,13 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mSurfaceTexture = surfaceTexture; } - public void clearSurfaceTextureLocked() { - if (mSurfaceTexture != null) { - mSurfaceTexture = null; + public void destroyLocked() { + mSurfaceTexture = null; + if (mSurface != null) { + mSurface.release(); + mSurface = null; } - sendTraversalRequestLocked(); + SurfaceControl.destroyDisplay(getDisplayTokenLocked()); } @Override @@ -225,12 +227,6 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mSurface = new Surface(mSurfaceTexture); } setSurfaceInTransactionLocked(mSurface); - } else { - setSurfaceInTransactionLocked(null); - if (mSurface != null) { - mSurface.destroy(); - mSurface = null; - } } } @@ -307,7 +303,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { public void onWindowDestroyed() { synchronized (getSyncRoot()) { if (mDevice != null) { - mDevice.clearSurfaceTextureLocked(); + mDevice.destroyLocked(); sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED); } } diff --git a/services/java/com/android/server/display/VirtualDisplayAdapter.java b/services/java/com/android/server/display/VirtualDisplayAdapter.java index 3a71361..46d473c 100644 --- a/services/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/java/com/android/server/display/VirtualDisplayAdapter.java @@ -58,7 +58,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { try { appToken.linkToDeath(device, 0); } catch (RemoteException ex) { - device.releaseLocked(); + device.destroyLocked(); return null; } @@ -72,6 +72,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) { VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); if (device != null) { + device.destroyLocked(); appToken.unlinkToDeath(device, 0); } @@ -85,6 +86,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { if (device != null) { Slog.i(TAG, "Virtual display device released because application token died: " + device.mOwnerPackageName); + device.destroyLocked(); sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); } } @@ -100,7 +102,6 @@ final class VirtualDisplayAdapter extends DisplayAdapter { private final int mDensityDpi; private final int mFlags; - private boolean mReleased; private Surface mSurface; private DisplayDeviceInfo mInfo; @@ -122,24 +123,25 @@ final class VirtualDisplayAdapter extends DisplayAdapter { @Override public void binderDied() { synchronized (getSyncRoot()) { - if (!mReleased) { + if (mSurface != null) { handleBinderDiedLocked(mAppToken); } } } - public void releaseLocked() { - mReleased = true; - sendTraversalRequestLocked(); + public void destroyLocked() { + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + SurfaceControl.destroyDisplay(getDisplayTokenLocked()); } @Override public void performTraversalInTransactionLocked() { - if (mReleased && mSurface != null) { - mSurface.destroy(); - mSurface = null; + if (mSurface != null) { + setSurfaceInTransactionLocked(mSurface); } - setSurfaceInTransactionLocked(mSurface); } @Override diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java index 11d3819..a9da30f 100644 --- a/services/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/java/com/android/server/display/WifiDisplayAdapter.java @@ -374,7 +374,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { private void removeDisplayDeviceLocked() { if (mDisplayDevice != null) { - mDisplayDevice.clearSurfaceLocked(); + mDisplayDevice.destroyLocked(); sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED); mDisplayDevice = null; @@ -633,9 +633,12 @@ final class WifiDisplayAdapter extends DisplayAdapter { mSurface = surface; } - public void clearSurfaceLocked() { - mSurface = null; - sendTraversalRequestLocked(); + public void destroyLocked() { + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + SurfaceControl.destroyDisplay(getDisplayTokenLocked()); } public void setNameLocked(String name) { @@ -645,7 +648,9 @@ final class WifiDisplayAdapter extends DisplayAdapter { @Override public void performTraversalInTransactionLocked() { - setSurfaceInTransactionLocked(mSurface); + if (mSurface != null) { + setSurfaceInTransactionLocked(mSurface); + } } @Override diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java new file mode 100644 index 0000000..469f7ce --- /dev/null +++ b/services/java/com/android/server/location/FlpHardwareProvider.java @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import android.hardware.location.GeofenceHardwareImpl; +import android.hardware.location.IFusedLocationHardware; +import android.hardware.location.IFusedLocationHardwareSink; +import android.location.IFusedGeofenceHardware; +import android.location.FusedBatchOptions; +import android.location.Geofence; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; +import android.util.Slog; + +/** + * This class is an interop layer for JVM types and the JNI code that interacts + * with the FLP HAL implementation. + * + * {@hide} + */ +public class FlpHardwareProvider { + private GeofenceHardwareImpl mGeofenceHardwareSink = null; + private IFusedLocationHardwareSink mLocationSink = null; + + private static FlpHardwareProvider sSingletonInstance = null; + + private final static String TAG = "FlpHardwareProvider"; + private final Context mContext; + + public static FlpHardwareProvider getInstance(Context context) { + if (sSingletonInstance == null) { + sSingletonInstance = new FlpHardwareProvider(context); + } + + return sSingletonInstance; + } + + private FlpHardwareProvider(Context context) { + mContext = context; + + // register for listening for passive provider data + Handler handler = new Handler(); + LocationManager manager = (LocationManager) mContext.getSystemService( + Context.LOCATION_SERVICE); + manager.requestLocationUpdates( + LocationManager.PASSIVE_PROVIDER, + 0 /* minTime */, + 0 /* minDistance */, + new NetworkLocationListener(), + handler.getLooper()); + } + + public static boolean isSupported() { + return nativeIsSupported(); + } + + /** + * Private callback functions used by FLP HAL. + */ + // FlpCallbacks members + private void onLocationReport(Location[] locations) { + for (Location location : locations) { + location.setProvider(LocationManager.FUSED_PROVIDER); + // set the elapsed time-stamp just as GPS provider does + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + } + + try { + if (mLocationSink != null) { + mLocationSink.onLocationAvailable(locations); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling onLocationAvailable"); + } + } + + // FlpDiagnosticCallbacks members + private void onDataReport(String data) { + try { + if (mLocationSink != null) { + mLocationSink.onDiagnosticDataAvailable(data); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable"); + } + } + + // FlpGeofenceCallbacks members + private void onGeofenceTransition( + int geofenceId, + Location location, + int transition, + long timestamp, + int sourcesUsed + ) { + // TODO: [GeofenceIntegration] change GeofenceHardwareImpl to accept a location object + } + + private void onGeofenceMonitorStatus(int status, int source, Location location) { + // TODO: [GeofenceIntegration] + } + + private void onGeofenceAdd(int geofenceId, int result) { + // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status + } + + private void onGeofenceRemove(int geofenceId, int result) { + // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status + } + + private void onGeofencePause(int geofenceId, int result) { + // TODO; [GeofenceIntegration] map between GPS and FLP results + } + + private void onGeofenceResume(int geofenceId, int result) { + // TODO: [GeofenceIntegration] map between GPS and FLP results + } + + /** + * Private native methods accessing FLP HAL. + */ + static { nativeClassInit(); } + + // Core members + private static native void nativeClassInit(); + private static native boolean nativeIsSupported(); + + // FlpLocationInterface members + private native void nativeInit(); + private native int nativeGetBatchSize(); + private native void nativeStartBatching(int requestId, FusedBatchOptions options); + private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject); + private native void nativeStopBatching(int id); + private native void nativeRequestBatchedLocation(int lastNLocations); + private native void nativeInjectLocation(Location location); + // TODO [Fix] sort out the lifetime of the instance + private native void nativeCleanup(); + + // FlpDiagnosticsInterface members + private native boolean nativeIsDiagnosticSupported(); + private native void nativeInjectDiagnosticData(String data); + + // FlpDeviceContextInterface members + private native boolean nativeIsDeviceContextSupported(); + private native void nativeInjectDeviceContext(int deviceEnabledContext); + + // FlpGeofencingInterface members + private native boolean nativeIsGeofencingSupported(); + private native void nativeAddGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray); + private native void nativePauseGeofence(int geofenceId); + private native void nativeResumeGeofence(int geofenceId, int monitorTransitions); + private native void nativeModifyGeofenceOption( + int geofenceId, + int lastTransition, + int monitorTransitions, + int notificationResponsiveness, + int unknownTimer, + int sourcesToUse); + private native void nativeRemoveGeofences(int[] geofenceIdsArray); + + /** + * Interface implementations for services built on top of this functionality. + */ + public static final String LOCATION = "Location"; + public static final String GEOFENCING = "Geofencing"; + + public IFusedLocationHardware getLocationHardware() { + nativeInit(); + return mLocationHardware; + } + + public IFusedGeofenceHardware getGeofenceHardware() { + nativeInit(); + return mGeofenceHardwareService; + } + + private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() { + @Override + public void registerSink(IFusedLocationHardwareSink eventSink) { + // only one sink is allowed at the moment + if (mLocationSink != null) { + throw new RuntimeException("IFusedLocationHardware does not support multiple sinks"); + } + + mLocationSink = eventSink; + } + + @Override + public void unregisterSink(IFusedLocationHardwareSink eventSink) { + // don't throw if the sink is not registered, simply make it a no-op + if (mLocationSink == eventSink) { + mLocationSink = null; + } + } + + @Override + public int getSupportedBatchSize() { + return nativeGetBatchSize(); + } + + @Override + public void startBatching(int requestId, FusedBatchOptions options) { + nativeStartBatching(requestId, options); + } + + @Override + public void stopBatching(int requestId) { + nativeStopBatching(requestId); + } + + @Override + public void updateBatchingOptions(int requestId, FusedBatchOptions options) { + nativeUpdateBatchingOptions(requestId, options); + } + + @Override + public void requestBatchOfLocations(int batchSizeRequested) { + nativeRequestBatchedLocation(batchSizeRequested); + } + + @Override + public boolean supportsDiagnosticDataInjection() { + return nativeIsDiagnosticSupported(); + } + + @Override + public void injectDiagnosticData(String data) { + nativeInjectDiagnosticData(data); + } + + @Override + public boolean supportsDeviceContextInjection() { + return nativeIsDeviceContextSupported(); + } + + @Override + public void injectDeviceContext(int deviceEnabledContext) { + nativeInjectDeviceContext(deviceEnabledContext); + } + }; + + private final IFusedGeofenceHardware mGeofenceHardwareService = + new IFusedGeofenceHardware.Stub() { + @Override + public boolean isSupported() { + return nativeIsGeofencingSupported(); + } + + @Override + public void addGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray) { + nativeAddGeofences(geofenceIdsArray, geofencesArray); + } + + @Override + public void removeGeofences(int[] geofenceIds) { + nativeRemoveGeofences(geofenceIds); + } + + @Override + public void pauseMonitoringGeofence(int geofenceId) { + nativePauseGeofence(geofenceId); + } + + @Override + public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) { + nativeResumeGeofence(geofenceId, monitorTransitions); + } + + @Override + public void modifyGeofenceOptions(int geofenceId, + int lastTransition, + int monitorTransitions, + int notificationResponsiveness, + int unknownTimer + ) { + // TODO: [GeofenceIntegration] set sourcesToUse to the right value + // TODO: expose sourcesToUse externally when needed + nativeModifyGeofenceOption( + geofenceId, + lastTransition, + monitorTransitions, + notificationResponsiveness, + unknownTimer, + /* sourcesToUse */ 0xFFFF); + } + }; + + /** + * Internal classes and functions used by the provider. + */ + private final class NetworkLocationListener implements LocationListener { + @Override + public void onLocationChanged(Location location) { + if ( + !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) || + !location.hasAccuracy() + ) { + return; + } + + nativeInjectLocation(location); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { } + + @Override + public void onProviderEnabled(String provider) { } + + @Override + public void onProviderDisabled(String provider) { } + } + + private GeofenceHardwareImpl getGeofenceHardwareSink() { + if (mGeofenceHardwareSink == null) { + // TODO: [GeofenceIntegration] we need to register ourselves with GeofenceHardwareImpl + mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext); + } + + return mGeofenceHardwareSink; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/java/com/android/server/location/FusedLocationHardwareSecure.java new file mode 100644 index 0000000..389bd24 --- /dev/null +++ b/services/java/com/android/server/location/FusedLocationHardwareSecure.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import android.content.Context; +import android.hardware.location.IFusedLocationHardware; +import android.hardware.location.IFusedLocationHardwareSink; +import android.location.FusedBatchOptions; +import android.os.RemoteException; + +/** + * FusedLocationHardware decorator that adds permission checking. + * @hide + */ +public class FusedLocationHardwareSecure extends IFusedLocationHardware.Stub { + private final IFusedLocationHardware mLocationHardware; + private final Context mContext; + private final String mPermissionId; + + public FusedLocationHardwareSecure( + IFusedLocationHardware locationHardware, + Context context, + String permissionId) { + mLocationHardware = locationHardware; + mContext = context; + mPermissionId = permissionId; + } + + private void checkPermissions() { + mContext.enforceCallingPermission( + mPermissionId, + String.format( + "Permission '%s' not granted to access FusedLocationHardware", + mPermissionId)); + } + + @Override + public void registerSink(IFusedLocationHardwareSink eventSink) throws RemoteException { + checkPermissions(); + mLocationHardware.registerSink(eventSink); + } + + @Override + public void unregisterSink(IFusedLocationHardwareSink eventSink) throws RemoteException { + checkPermissions(); + mLocationHardware.unregisterSink(eventSink); + } + + @Override + public int getSupportedBatchSize() throws RemoteException { + checkPermissions(); + return mLocationHardware.getSupportedBatchSize(); + } + + @Override + public void startBatching(int id, FusedBatchOptions batchOptions) throws RemoteException { + checkPermissions(); + mLocationHardware.startBatching(id, batchOptions); + } + + @Override + public void stopBatching(int id) throws RemoteException { + checkPermissions(); + mLocationHardware.stopBatching(id); + } + + @Override + public void updateBatchingOptions( + int id, + FusedBatchOptions batchoOptions + ) throws RemoteException { + checkPermissions(); + mLocationHardware.updateBatchingOptions(id, batchoOptions); + } + + @Override + public void requestBatchOfLocations(int batchSizeRequested) throws RemoteException { + checkPermissions(); + mLocationHardware.requestBatchOfLocations(batchSizeRequested); + } + + @Override + public boolean supportsDiagnosticDataInjection() throws RemoteException { + checkPermissions(); + return mLocationHardware.supportsDiagnosticDataInjection(); + } + + @Override + public void injectDiagnosticData(String data) throws RemoteException { + checkPermissions(); + mLocationHardware.injectDiagnosticData(data); + } + + @Override + public boolean supportsDeviceContextInjection() throws RemoteException { + checkPermissions(); + return mLocationHardware.supportsDeviceContextInjection(); + } + + @Override + public void injectDeviceContext(int deviceEnabledContext) throws RemoteException { + checkPermissions(); + mLocationHardware.injectDeviceContext(deviceEnabledContext); + } +} diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/java/com/android/server/location/FusedProxy.java new file mode 100644 index 0000000..8278b96 --- /dev/null +++ b/services/java/com/android/server/location/FusedProxy.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (The "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import com.android.server.ServiceWatcher; + +import android.Manifest; +import android.content.Context; +import android.hardware.location.IFusedLocationHardware; +import android.location.IFusedProvider; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; + +/** + * Proxy that helps bind GCore FusedProvider implementations to the Fused Hardware instances. + * + * @hide + */ +public final class FusedProxy { + private final String TAG = "FusedProxy"; + + private ServiceWatcher mServiceWatcher; + + private FusedLocationHardwareSecure mLocationHardware; + + /** + * Constructor of the class. + * This is private as the class follows a factory pattern for construction. + * + * @param context The context needed for construction. + * @param handler The handler needed for construction. + * @param locationHardware The instance of the Fused location hardware assigned to the proxy. + */ + private FusedProxy(Context context, Handler handler, IFusedLocationHardware locationHardware) { + mLocationHardware = new FusedLocationHardwareSecure( + locationHardware, + context, + Manifest.permission.LOCATION_HARDWARE); + Runnable newServiceWork = new Runnable() { + @Override + public void run() { + bindProvider(mLocationHardware); + } + }; + + // prepare the connection to the provider + mServiceWatcher = new ServiceWatcher( + context, + TAG, + "com.android.location.service.FusedProvider", + com.android.internal.R.bool.config_enableFusedLocationOverlay, + com.android.internal.R.string.config_fusedLocationProviderPackageName, + com.android.internal.R.array.config_locationProviderPackageNames, + newServiceWork, + handler); + } + + /** + * Creates an instance of the proxy and binds it to the appropriate FusedProvider. + * + * @param context The context needed for construction. + * @param handler The handler needed for construction. + * @param locationHardware The instance of the Fused location hardware assigned to the proxy. + * + * @return An instance of the proxy if it could be bound, null otherwise. + */ + public static FusedProxy createAndBind( + Context context, + Handler handler, + IFusedLocationHardware locationHardware + ) { + FusedProxy fusedProxy = new FusedProxy(context, handler, locationHardware); + + // try to bind the Fused provider + if (!fusedProxy.mServiceWatcher.start()) { + return null; + } + + return fusedProxy; + } + + /** + * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance. + * + * @param locationHardware The FusedLocationHardware instance to use for the binding operation. + */ + private void bindProvider(IFusedLocationHardware locationHardware) { + IFusedProvider provider = IFusedProvider.Stub.asInterface(mServiceWatcher.getBinder()); + + if (provider == null) { + Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected."); + return; + } + + try { + provider.onFusedLocationHardwareChange(locationHardware); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } +} diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 163536a..e78362b 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -22,6 +22,8 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.os.Process.SYSTEM_UID; +import static android.os.Process.PACKAGE_INFO_GID; import android.content.IntentFilter; import android.content.pm.ActivityInfo; @@ -117,6 +119,7 @@ final class Settings { private final File mPackageListFilename; private final File mStoppedPackagesFilename; private final File mBackupStoppedPackagesFilename; + final HashMap<String, PackageSetting> mPackages = new HashMap<String, PackageSetting>(); // List of replaced system applications @@ -201,6 +204,8 @@ final class Settings { mSettingsFilename = new File(mSystemDir, "packages.xml"); mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml"); mPackageListFilename = new File(mSystemDir, "packages.list"); + FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID); + // Deprecated: Needed for migration mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml"); mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml"); @@ -1369,13 +1374,15 @@ final class Settings { -1, -1); // Write package list file now, use a JournaledFile. - // - File tempFile = new File(mPackageListFilename.toString() + ".tmp"); + File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp"); JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile); - fstr = new FileOutputStream(journal.chooseForWrite()); + final File writeTarget = journal.chooseForWrite(); + fstr = new FileOutputStream(writeTarget); str = new BufferedOutputStream(fstr); try { + FileUtils.setPermissions(fstr.getFD(), 0660, SYSTEM_UID, PACKAGE_INFO_GID); + StringBuilder sb = new StringBuilder(); for (final PackageSetting pkg : mPackages.values()) { ApplicationInfo ai = pkg.pkg.applicationInfo; @@ -1400,6 +1407,7 @@ final class Settings { // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: // system/core/run-as/run-as.c + // system/core/sdcard/sdcard.c // sb.setLength(0); sb.append(ai.packageName); @@ -1421,11 +1429,6 @@ final class Settings { journal.rollback(); } - FileUtils.setPermissions(mPackageListFilename.toString(), - FileUtils.S_IRUSR|FileUtils.S_IWUSR - |FileUtils.S_IRGRP|FileUtils.S_IWGRP, - -1, -1); - writeAllUsersPackageRestrictionsLPr(); return; diff --git a/services/jni/Android.mk b/services/jni/Android.mk index 3946f15..93d8e07 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ com_android_server_UsbHostManager.cpp \ com_android_server_VibratorService.cpp \ com_android_server_location_GpsLocationProvider.cpp \ + com_android_server_location_FlpHardwareProvider.cpp \ com_android_server_connectivity_Vpn.cpp \ onload.cpp diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp new file mode 100644 index 0000000..48b86db --- /dev/null +++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -0,0 +1,901 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.apache.org/license/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. + */ + +#define LOG_TAG "FuseLocationProvider" +#define LOG_NDEBUG 0 + +#define WAKE_LOCK_NAME "FLP" +#define LOCATION_CLASS_NAME "android/location/Location" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" +#include "hardware/fused_location.h" +#include "hardware_legacy/power.h" + +static jobject sCallbacksObj = NULL; +static JNIEnv *sCallbackEnv = NULL; +static hw_device_t* sHardwareDevice = NULL; + +static jmethodID sOnLocationReport = NULL; +static jmethodID sOnDataReport = NULL; +static jmethodID sOnGeofenceTransition = NULL; +static jmethodID sOnGeofenceMonitorStatus = NULL; +static jmethodID sOnGeofenceAdd = NULL; +static jmethodID sOnGeofenceRemove = NULL; +static jmethodID sOnGeofencePause = NULL; +static jmethodID sOnGeofenceResume = NULL; + +static const FlpLocationInterface* sFlpInterface = NULL; +static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL; +static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL; +static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL; + +namespace android { + +static inline void CheckExceptions(JNIEnv* env, const char* methodName) { + if(!env->ExceptionCheck()) { + return; + } + + ALOGE("An exception was thrown by '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); +} + +static inline void ThrowOnError( + JNIEnv* env, + int resultCode, + const char* methodName) { + if(resultCode == FLP_RESULT_SUCCESS) { + return; + } + + ALOGE("Error %d in '%s'", resultCode, methodName); + jclass exceptionClass = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(exceptionClass, methodName); +} + +static bool IsValidCallbackThread() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + if(sCallbackEnv == NULL || sCallbackEnv != env) { + ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv); + return false; + } + + return true; +} + +static int SetThreadEvent(ThreadEvent event) { + JavaVM* javaVm = AndroidRuntime::getJavaVM(); + + switch(event) { + case ASSOCIATE_JVM: + { + if(sCallbackEnv != NULL) { + ALOGE( + "Attempted to associate callback in '%s'. Callback already associated.", + __FUNCTION__ + ); + return FLP_RESULT_ERROR; + } + + JavaVMAttachArgs args = { + JNI_VERSION_1_6, + "FLP Service Callback Thread", + /* group */ NULL + }; + + jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args); + if (attachResult != 0) { + ALOGE("Callback thread attachment error: %d", attachResult); + return FLP_RESULT_ERROR; + } + + ALOGV("Callback thread attached: %p", sCallbackEnv); + break; + } + case DISASSOCIATE_JVM: + { + if (!IsValidCallbackThread()) { + ALOGE( + "Attempted to dissasociate an unnownk callback thread : '%s'.", + __FUNCTION__ + ); + return FLP_RESULT_ERROR; + } + + if (javaVm->DetachCurrentThread() != 0) { + return FLP_RESULT_ERROR; + } + + sCallbackEnv = NULL; + break; + } + default: + ALOGE("Invalid ThreadEvent request %d", event); + return FLP_RESULT_ERROR; + } + + return FLP_RESULT_SUCCESS; +} + +/* + * Initializes the FlpHardwareProvider class from the native side by opening + * the HW module and obtaining the proper interfaces. + */ +static void ClassInit(JNIEnv* env, jclass clazz) { + // get references to the Java provider methods + sOnLocationReport = env->GetMethodID( + clazz, + "onLocationReport", + "([Landroid/location/Location;)V"); + sOnDataReport = env->GetMethodID( + clazz, + "onDataReport", + "(Ljava/lang/String;)V" + ); + sOnGeofenceTransition = env->GetMethodID( + clazz, + "onGeofenceTransition", + "(ILandroid/location/Location;IJI)V" + ); + sOnGeofenceMonitorStatus = env->GetMethodID( + clazz, + "onGeofenceMonitorStatus", + "(IILandroid/location/Location;)V" + ); + sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V"); + sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V"); + sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V"); + sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V"); +} + +/* + * Helper function to unwrap a java object back into a FlpLocation structure. + */ +static void TranslateFromObject( + JNIEnv* env, + jobject locationObject, + FlpLocation& location) { + location.size = sizeof(FlpLocation); + location.flags = 0; + + jclass locationClass = env->GetObjectClass(locationObject); + + jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D"); + location.latitude = env->CallDoubleMethod(locationObject, getLatitude); + jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D"); + location.longitude = env->CallDoubleMethod(locationObject, getLongitude); + jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J"); + location.timestamp = env->CallLongMethod(locationObject, getTime); + location.flags |= FLP_LOCATION_HAS_LAT_LONG; + + jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z"); + if (env->CallBooleanMethod(locationObject, hasAltitude)) { + jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D"); + location.altitude = env->CallDoubleMethod(locationObject, getAltitude); + location.flags |= FLP_LOCATION_HAS_ALTITUDE; + } + + jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z"); + if (env->CallBooleanMethod(locationObject, hasSpeed)) { + jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F"); + location.speed = env->CallFloatMethod(locationObject, getSpeed); + location.flags |= FLP_LOCATION_HAS_SPEED; + } + + jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z"); + if (env->CallBooleanMethod(locationObject, hasBearing)) { + jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F"); + location.bearing = env->CallFloatMethod(locationObject, getBearing); + location.flags |= FLP_LOCATION_HAS_BEARING; + } + + jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z"); + if (env->CallBooleanMethod(locationObject, hasAccuracy)) { + jmethodID getAccuracy = env->GetMethodID( + locationClass, + "getAccuracy", + "()F" + ); + location.accuracy = env->CallFloatMethod(locationObject, getAccuracy); + location.flags |= FLP_LOCATION_HAS_ACCURACY; + } + + // TODO: wire sources_used if Location class exposes them +} + +/* + * Helper function to unwrap FlpBatchOptions from the Java Runtime calls. + */ +static void TranslateFromObject( + JNIEnv* env, + jobject batchOptionsObject, + FlpBatchOptions& batchOptions) { + jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject); + + jmethodID getMaxPower = env->GetMethodID( + batchOptionsClass, + "getMaxPowerAllocationInMW", + "()D" + ); + batchOptions.max_power_allocation_mW = env->CallDoubleMethod( + batchOptionsObject, + getMaxPower + ); + + jmethodID getPeriod = env->GetMethodID( + batchOptionsClass, + "getPeriodInNS", + "()J" + ); + batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod); + + jmethodID getSourcesToUse = env->GetMethodID( + batchOptionsClass, + "getSourcesToUse", + "()I" + ); + batchOptions.sources_to_use = env->CallIntMethod( + batchOptionsObject, + getSourcesToUse + ); + + jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I"); + batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags); +} + +/* + * Helper function to transform FlpLocation into a java object. + */ +static void TranslateToObject(const FlpLocation* location, jobject& locationObject) { + jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME); + jmethodID locationCtor = sCallbackEnv->GetMethodID( + locationClass, + "<init>", + "(Ljava/lang/String;)V" + ); + + // the provider is set in the upper JVM layer + locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL); + jint flags = location->flags; + + // set the valid information in the object + if (flags & FLP_LOCATION_HAS_LAT_LONG) { + jmethodID setLatitude = sCallbackEnv->GetMethodID( + locationClass, + "setLatitude", + "(D)V" + ); + sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude); + + jmethodID setLongitude = sCallbackEnv->GetMethodID( + locationClass, + "setLongitude", + "(D)V" + ); + sCallbackEnv->CallVoidMethod( + locationObject, + setLongitude, + location->longitude + ); + + jmethodID setTime = sCallbackEnv->GetMethodID( + locationClass, + "setTime", + "(J)V" + ); + sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp); + } + + if (flags & FLP_LOCATION_HAS_ALTITUDE) { + jmethodID setAltitude = sCallbackEnv->GetMethodID( + locationClass, + "setAltitude", + "(D)V" + ); + sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude); + } + + if (flags & FLP_LOCATION_HAS_SPEED) { + jmethodID setSpeed = sCallbackEnv->GetMethodID( + locationClass, + "setSpeed", + "(F)V" + ); + sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed); + } + + if (flags & FLP_LOCATION_HAS_BEARING) { + jmethodID setBearing = sCallbackEnv->GetMethodID( + locationClass, + "setBearing", + "(F)V" + ); + sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing); + } + + if (flags & FLP_LOCATION_HAS_ACCURACY) { + jmethodID setAccuracy = sCallbackEnv->GetMethodID( + locationClass, + "setAccuracy", + "(F)V" + ); + sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy); + } + + // TODO: wire FlpLocation::sources_used when needed +} + +/* + * Helper function to serialize FlpLocation structures. + */ +static void TranslateToObjectArray( + int32_t locationsCount, + FlpLocation** locations, + jobjectArray& locationsArray) { + jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME); + locationsArray = sCallbackEnv->NewObjectArray( + locationsCount, + locationClass, + /* initialElement */ NULL + ); + + for (int i = 0; i < locationsCount; ++i) { + jobject locationObject = NULL; + TranslateToObject(locations[i], locationObject); + sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject); + sCallbackEnv->DeleteLocalRef(locationObject); + } +} + +static void LocationCallback(int32_t locationsCount, FlpLocation** locations) { + if(!IsValidCallbackThread()) { + return; + } + + if(locationsCount == 0 || locations == NULL) { + ALOGE( + "Invalid LocationCallback. Count: %d, Locations: %p", + locationsCount, + locations + ); + return; + } + + jobjectArray locationsArray = NULL; + TranslateToObjectArray(locationsCount, locations, locationsArray); + + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sOnLocationReport, + locationsArray + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +static void AcquireWakelock() { + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); +} + +static void ReleaseWakelock() { + release_wake_lock(WAKE_LOCK_NAME); +} + +FlpCallbacks sFlpCallbacks = { + sizeof(FlpCallbacks), + LocationCallback, + AcquireWakelock, + ReleaseWakelock, + SetThreadEvent +}; + +static void ReportData(char* data, int length) { + jstring stringData = NULL; + + if(length != 0 && data != NULL) { + stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length); + } else { + ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data); + return; + } + + sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = { + sizeof(FlpDiagnosticCallbacks), + SetThreadEvent, + ReportData +}; + +static void GeofenceTransitionCallback( + int32_t geofenceId, + FlpLocation* location, + int32_t transition, + FlpUtcTime timestamp, + uint32_t sourcesUsed + ) { + if(!IsValidCallbackThread()) { + return; + } + + if(location == NULL) { + ALOGE("GeofenceTransition received with invalid location: %p", location); + return; + } + + jobject locationObject = NULL; + TranslateToObject(location, locationObject); + + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sOnGeofenceTransition, + geofenceId, + locationObject, + transition, + timestamp, + sourcesUsed + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +static void GeofenceMonitorStatusCallback( + int32_t status, + uint32_t source, + FlpLocation* lastLocation) { + if(!IsValidCallbackThread()) { + return; + } + + jobject locationObject = NULL; + if(lastLocation != NULL) { + TranslateToObject(lastLocation, locationObject); + } + + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sOnGeofenceMonitorStatus, + status, + source, + locationObject + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +static void GeofenceAddCallback(int32_t geofenceId, int32_t result) { + if(!IsValidCallbackThread()) { + return; + } + + sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) { + if(!IsValidCallbackThread()) { + return; + } + + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sOnGeofenceRemove, + geofenceId, + result + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +static void GeofencePauseCallback(int32_t geofenceId, int32_t result) { + if(!IsValidCallbackThread()) { + return; + } + + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sOnGeofencePause, + geofenceId, + result + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) { + if(!IsValidCallbackThread()) { + return; + } + + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sOnGeofenceResume, + geofenceId, + result + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); +} + +FlpGeofenceCallbacks sFlpGeofenceCallbacks = { + sizeof(FlpGeofenceCallbacks), + GeofenceTransitionCallback, + GeofenceMonitorStatusCallback, + GeofenceAddCallback, + GeofenceRemoveCallback, + GeofencePauseCallback, + GeofenceResumeCallback, + SetThreadEvent +}; + +/* + * Initializes the Fused Location Provider in the native side. It ensures that + * the Flp interfaces are initialized properly. + */ +static void Init(JNIEnv* env, jobject obj) { + if(sHardwareDevice != NULL) { + ALOGD("Hardware Device already opened."); + return; + } + + const hw_module_t* module = NULL; + int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module); + if(err != 0) { + ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err); + return; + } + + err = module->methods->open( + module, + FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice); + if(err != 0) { + ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err); + return; + } + + sFlpInterface = NULL; + flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice); + sFlpInterface = flp_device->get_flp_interface(flp_device); + + if(sFlpInterface != NULL) { + sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>( + sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE) + ); + + sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>( + sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE) + ); + + sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>( + sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE) + ); + } + + if(sCallbacksObj == NULL) { + sCallbacksObj = env->NewGlobalRef(obj); + } + + // initialize the Flp interfaces + if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + if(sFlpDiagnosticInterface != NULL) { + sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks); + } + + if(sFlpGeofencingInterface != NULL) { + sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks); + } + + // TODO: inject any device context if when needed +} + +static jboolean IsSupported(JNIEnv* env, jclass clazz) { + return sFlpInterface != NULL; +} + +static jint GetBatchSize(JNIEnv* env, jobject object) { + if(sFlpInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + return sFlpInterface->get_batch_size(); +} + +static void StartBatching( + JNIEnv* env, + jobject object, + jint id, + jobject optionsObject) { + if(sFlpInterface == NULL || optionsObject == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + FlpBatchOptions options; + TranslateFromObject(env, optionsObject, options); + int result = sFlpInterface->start_batching(id, &options); + ThrowOnError(env, result, __FUNCTION__); +} + +static void UpdateBatchingOptions( + JNIEnv* env, + jobject object, + jint id, + jobject optionsObject) { + if(sFlpInterface == NULL || optionsObject == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + FlpBatchOptions options; + TranslateFromObject(env, optionsObject, options); + int result = sFlpInterface->update_batching_options(id, &options); + ThrowOnError(env, result, __FUNCTION__); +} + +static void StopBatching(JNIEnv* env, jobject object, jint id) { + if(sFlpInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + sFlpInterface->stop_batching(id); +} + +static void Cleanup(JNIEnv* env, jobject object) { + if(sFlpInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + sFlpInterface->cleanup(); + + if(sCallbacksObj != NULL) { + env->DeleteGlobalRef(sCallbacksObj); + sCallbacksObj = NULL; + } + + sFlpInterface = NULL; + sFlpDiagnosticInterface = NULL; + sFlpDeviceContextInterface = NULL; + sFlpGeofencingInterface = NULL; + + if(sHardwareDevice != NULL) { + sHardwareDevice->close(sHardwareDevice); + sHardwareDevice = NULL; + } +} + +static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) { + if(sFlpInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + sFlpInterface->get_batched_location(lastNLocations); +} + +static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) { + if(locationObject == NULL) { + ALOGE("Invalid location for injection: %p", locationObject); + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + if(sFlpInterface == NULL) { + // there is no listener, bail + return; + } + + FlpLocation location; + TranslateFromObject(env, locationObject, location); + int result = sFlpInterface->inject_location(&location); + if (result != FLP_RESULT_ERROR) { + // do not throw but log, this operation should be fire and forget + ALOGE("Error %d in '%s'", result, __FUNCTION__); + } +} + +static jboolean IsDiagnosticSupported() { + return sFlpDiagnosticInterface != NULL; +} + +static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) { + if(stringData == NULL) { + ALOGE("Invalid diagnostic data for injection: %p", stringData); + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + if(sFlpDiagnosticInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + int length = env->GetStringLength(stringData); + const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL); + if(data == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + int result = sFlpDiagnosticInterface->inject_data((char*) data, length); + ThrowOnError(env, result, __FUNCTION__); +} + +static jboolean IsDeviceContextSupported() { + return sFlpDeviceContextInterface != NULL; +} + +static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) { + if(sFlpDeviceContextInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + int result = sFlpDeviceContextInterface->inject_device_context(enabledMask); + ThrowOnError(env, result, __FUNCTION__); +} + +static jboolean IsGeofencingSupported() { + return sFlpGeofencingInterface != NULL; +} + +static void AddGeofences( + JNIEnv* env, + jobject object, + jintArray geofenceIdsArray, + jobjectArray geofencesArray) { + if(geofencesArray == NULL) { + ALOGE("Invalid Geofences to add: %p", geofencesArray); + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + if (sFlpGeofencingInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + jint geofencesCount = env->GetArrayLength(geofenceIdsArray); + Geofence* geofences = new Geofence[geofencesCount]; + if (geofences == NULL) { + ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__); + } + + jint* ids = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL); + for (int i = 0; i < geofencesCount; ++i) { + geofences[i].geofence_id = ids[i]; + + // TODO: fill in the GeofenceData + + // TODO: fill in the GeofenceOptions + } + + sFlpGeofencingInterface->add_geofences(geofencesCount, &geofences); + if (geofences != NULL) delete[] geofences; +} + +static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) { + if(sFlpGeofencingInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + sFlpGeofencingInterface->pause_geofence(geofenceId); +} + +static void ResumeGeofence( + JNIEnv* env, + jobject object, + jint geofenceId, + jint monitorTransitions) { + if(sFlpGeofencingInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions); +} + +static void ModifyGeofenceOption( + JNIEnv* env, + jobject object, + jint geofenceId, + jint lastTransition, + jint monitorTransitions, + jint notificationResponsiveness, + jint unknownTimer, + jint sourcesToUse) { + if(sFlpGeofencingInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + GeofenceOptions options = { + lastTransition, + monitorTransitions, + notificationResponsiveness, + unknownTimer, + (uint32_t)sourcesToUse + }; + + sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options); +} + +static void RemoveGeofences( + JNIEnv* env, + jobject object, + jintArray geofenceIdsArray) { + if(sFlpGeofencingInterface == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray); + jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL); + if(geofenceIds == NULL) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + + sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds); +} + +static JNINativeMethod sMethods[] = { + //{"name", "signature", functionPointer } + {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)}, + {"nativeInit", "()V", reinterpret_cast<void*>(Init)}, + {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)}, + {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)}, + {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)}, + {"nativeStartBatching", + "(ILandroid/location/FusedBatchOptions;)V", + reinterpret_cast<void*>(StartBatching)}, + {"nativeUpdateBatchingOptions", + "(ILandroid/location/FusedBatchOptions;)V", + reinterpret_cast<void*>(UpdateBatchingOptions)}, + {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)}, + {"nativeRequestBatchedLocation", + "(I)V", + reinterpret_cast<void*>(GetBatchedLocation)}, + {"nativeInjectLocation", + "(Landroid/location/Location;)V", + reinterpret_cast<void*>(InjectLocation)}, + {"nativeIsDiagnosticSupported", + "()Z", + reinterpret_cast<void*>(IsDiagnosticSupported)}, + {"nativeInjectDiagnosticData", + "(Ljava/lang/String;)V", + reinterpret_cast<void*>(InjectDiagnosticData)}, + {"nativeIsDeviceContextSupported", + "()Z", + reinterpret_cast<void*>(IsDeviceContextSupported)}, + {"nativeInjectDeviceContext", + "(I)V", + reinterpret_cast<void*>(InjectDeviceContext)}, + {"nativeIsGeofencingSupported", + "()Z", + reinterpret_cast<void*>(IsGeofencingSupported)}, + {"nativeAddGeofences", + "([I[Landroid/location/Geofence;)V", + reinterpret_cast<void*>(AddGeofences)}, + {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)}, + {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)}, + {"nativeModifyGeofenceOption", + "(IIIIII)V", + reinterpret_cast<void*>(ModifyGeofenceOption)}, + {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)} +}; + +/* + * Registration method invoked on JNI Load. + */ +int register_android_server_location_FlpHardwareProvider(JNIEnv* env) { + return jniRegisterNativeMethods( + env, + "com/android/server/location/FlpHardwareProvider", + sMethods, + NELEM(sMethods) + ); +} + +} /* name-space Android */ diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index 736ef24..5427277 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -32,6 +32,7 @@ int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); int register_android_server_location_GpsLocationProvider(JNIEnv* env); +int register_android_server_location_FlpHardwareProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); int register_android_server_AssetAtlasService(JNIEnv* env); }; @@ -61,6 +62,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_VibratorService(env); register_android_server_SystemServer(env); register_android_server_location_GpsLocationProvider(env); + register_android_server_location_FlpHardwareProvider(env); register_android_server_connectivity_Vpn(env); register_android_server_AssetAtlasService(env); diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 4171bb5..361f5d7 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -1148,14 +1148,6 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - /*package*/ static void native_drawPicture(int nativeCanvas, - int nativePicture) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawPicture is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate /*package*/ static void finalizer(int nativeCanvas) { // get the delegate from the native int so that it can be disposed. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java index fe3c709..92b8e46 100644 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ b/wifi/java/android/net/wifi/WifiMonitor.java @@ -32,7 +32,10 @@ import android.util.Log; import com.android.internal.util.Protocol; import com.android.internal.util.StateMachine; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -44,6 +47,7 @@ import java.util.regex.Matcher; */ public class WifiMonitor { + private static final boolean DBG = false; private static final String TAG = "WifiMonitor"; /** Events we receive from the supplicant daemon */ @@ -279,9 +283,6 @@ public class WifiMonitor { /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; - private final StateMachine mStateMachine; - private final WifiNative mWifiNative; - /* Supplicant events reported to a state machine */ private static final int BASE = Protocol.BASE_WIFI_MONITOR; @@ -347,164 +348,324 @@ public class WifiMonitor { private static final String WPA_RECV_ERROR_STR = "recv error"; /** - * Tracks consecutive receive errors - */ - private int mRecvErrors = 0; - - /** * Max errors before we close supplicant connection */ private static final int MAX_RECV_ERRORS = 10; + private final String mInterfaceName; + private final WifiNative mWifiNative; + private final StateMachine mWifiStateMachine; + private boolean mMonitoring; + public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) { - mStateMachine = wifiStateMachine; + if (DBG) Log.d(TAG, "Creating WifiMonitor"); mWifiNative = wifiNative; + mInterfaceName = wifiNative.mInterfaceName; + mWifiStateMachine = wifiStateMachine; + mMonitoring = false; + + WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this); } public void startMonitoring() { - new MonitorThread().start(); + WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName); } - class MonitorThread extends Thread { - public MonitorThread() { - super("WifiMonitor"); + public void stopMonitoring() { + WifiMonitorSingleton.getMonitor().stopMonitoring(mInterfaceName); + } + + public void stopSupplicant() { + WifiMonitorSingleton.getMonitor().stopSupplicant(); + } + + public void killSupplicant(boolean p2pSupported) { + WifiMonitorSingleton.getMonitor().killSupplicant(p2pSupported); + } + + private static class WifiMonitorSingleton { + private static Object sSingletonLock = new Object(); + private static WifiMonitorSingleton sWifiMonitorSingleton = null; + private HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>(); + private boolean mConnected = false; + private WifiNative mWifiNative; + + private WifiMonitorSingleton() { } - public void run() { + static WifiMonitorSingleton getMonitor() { + if (DBG) Log.d(TAG, "WifiMonitorSingleton gotten"); + synchronized (sSingletonLock) { + if (sWifiMonitorSingleton == null) { + if (DBG) Log.d(TAG, "WifiMonitorSingleton created"); + sWifiMonitorSingleton = new WifiMonitorSingleton(); + } + } + return sWifiMonitorSingleton; + } - if (connectToSupplicant()) { - // Send a message indicating that it is now possible to send commands - // to the supplicant - mStateMachine.sendMessage(SUP_CONNECTION_EVENT); - } else { - mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + public synchronized void startMonitoring(String iface) { + WifiMonitor m = mIfaceMap.get(iface); + if (m == null) { + Log.e(TAG, "startMonitor called with unknown iface=" + iface); return; } + Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected); + + if (mConnected) { + m.mMonitoring = true; + m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT); + } else { + if (DBG) Log.d(TAG, "connecting to supplicant"); + int connectTries = 0; + while (true) { + if (mWifiNative.connectToSupplicant()) { + m.mMonitoring = true; + m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT); + new MonitorThread(mWifiNative, this).start(); + mConnected = true; + break; + } + if (connectTries++ < 5) { + try { + Thread.sleep(1000); + } catch (InterruptedException ignore) { + } + } else { + mIfaceMap.remove(iface); + m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + break; + } + } + } + } + + public synchronized void stopMonitoring(String iface) { + WifiMonitor m = mIfaceMap.get(iface); + if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mWifiStateMachine); + m.mMonitoring = false; + m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + } + + public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) { + if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mWifiStateMachine + ")"); + mIfaceMap.put(iface, m); + if (mWifiNative == null) { + mWifiNative = m.mWifiNative; + } + } + + public synchronized void unregisterInterfaceMonitor(String iface) { + // REVIEW: When should we call this? If this isn't called, then WifiMonitor + // objects will remain in the mIfaceMap; and won't ever get deleted + + WifiMonitor m = mIfaceMap.remove(iface); + if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mWifiStateMachine + ")"); + } + + public synchronized void stopSupplicant() { + mWifiNative.stopSupplicant(); + } + + public synchronized void killSupplicant(boolean p2pSupported) { + mWifiNative.killSupplicant(p2pSupported); + mConnected = false; + Iterator<Map.Entry<String, WifiMonitor>> it = mIfaceMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, WifiMonitor> e = it.next(); + WifiMonitor m = e.getValue(); + m.mMonitoring = false; + } + } + + private synchronized WifiMonitor getMonitor(String iface) { + return mIfaceMap.get(iface); + } + } + + private static class MonitorThread extends Thread { + private final WifiNative mWifiNative; + private final WifiMonitorSingleton mWifiMonitorSingleton; + private int mRecvErrors = 0; + private StateMachine mStateMachine = null; + + public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) { + super("WifiMonitor"); + mWifiNative = wifiNative; + mWifiMonitorSingleton = wifiMonitorSingleton; + } + + public void run() { //noinspection InfiniteLoopStatement for (;;) { String eventStr = mWifiNative.waitForEvent(); // Skip logging the common but mostly uninteresting scan-results event - if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { + if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { Log.d(TAG, "Event [" + eventStr + "]"); } - if (!eventStr.startsWith(EVENT_PREFIX_STR)) { - if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && - 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { - mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); - } else if (eventStr.startsWith(WPS_SUCCESS_STR)) { - mStateMachine.sendMessage(WPS_SUCCESS_EVENT); - } else if (eventStr.startsWith(WPS_FAIL_STR)) { - handleWpsFailEvent(eventStr); - } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { - mStateMachine.sendMessage(WPS_OVERLAP_EVENT); - } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { - mStateMachine.sendMessage(WPS_TIMEOUT_EVENT); - } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { - handleP2pEvents(eventStr); - } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { - handleHostApEvents(eventStr); + + WifiMonitor m = null; + mStateMachine = null; + + if (eventStr.startsWith("IFNAME=")) { + int space = eventStr.indexOf(' '); + if (space != -1) { + String iface = eventStr.substring(7,space); + m = mWifiMonitorSingleton.getMonitor(iface); + if (m != null) { + if (m.mMonitoring) { + mStateMachine = m.mWifiStateMachine; + eventStr = eventStr.substring(space + 1); + } + else { + if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface + + ") is stopped"); + continue; + } + } + else { + eventStr = eventStr.substring(space + 1); + } } - continue; } - String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); - int nameEnd = eventName.indexOf(' '); - if (nameEnd != -1) - eventName = eventName.substring(0, nameEnd); - if (eventName.length() == 0) { - if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name"); - continue; - } - /* - * Map event name into event enum - */ - int event; - if (eventName.equals(CONNECTED_STR)) - event = CONNECTED; - else if (eventName.equals(DISCONNECTED_STR)) - event = DISCONNECTED; - else if (eventName.equals(STATE_CHANGE_STR)) - event = STATE_CHANGE; - else if (eventName.equals(SCAN_RESULTS_STR)) - event = SCAN_RESULTS; - else if (eventName.equals(LINK_SPEED_STR)) - event = LINK_SPEED; - else if (eventName.equals(TERMINATING_STR)) - event = TERMINATING; - else if (eventName.equals(DRIVER_STATE_STR)) - event = DRIVER_STATE; - else if (eventName.equals(EAP_FAILURE_STR)) - event = EAP_FAILURE; - else if (eventName.equals(ASSOC_REJECT_STR)) - event = ASSOC_REJECT; - else - event = UNKNOWN; - - String eventData = eventStr; - if (event == DRIVER_STATE || event == LINK_SPEED) - eventData = eventData.split(" ")[1]; - else if (event == STATE_CHANGE || event == EAP_FAILURE) { - int ind = eventStr.indexOf(" "); - if (ind != -1) { - eventData = eventStr.substring(ind + 1); + if (mStateMachine != null) { + if (dispatchEvent(eventStr)) { + break; } } else { - int ind = eventStr.indexOf(" - "); - if (ind != -1) { - eventData = eventStr.substring(ind + 3); - } - } - - if (event == STATE_CHANGE) { - handleSupplicantStateChange(eventData); - } else if (event == DRIVER_STATE) { - handleDriverEvent(eventData); - } else if (event == TERMINATING) { - /** - * Close the supplicant connection if we see - * too many recv errors - */ - if (eventData.startsWith(WPA_RECV_ERROR_STR)) { - if (++mRecvErrors > MAX_RECV_ERRORS) { - if (false) { - Log.d(TAG, "too many recv errors, closing connection"); - } - } else { - continue; + if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id"); + boolean done = false; + Iterator<Map.Entry<String, WifiMonitor>> it = + mWifiMonitorSingleton.mIfaceMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, WifiMonitor> e = it.next(); + m = e.getValue(); + mStateMachine = m.mWifiStateMachine; + if (dispatchEvent(eventStr)) { + done = true; } } - // notify and exit - mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); - break; - } else if (event == EAP_FAILURE) { - if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { - mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); + if (done) { + // After this thread terminates, we'll no longer + // be connected to the supplicant + if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events"); + mWifiMonitorSingleton.mConnected = false; + break; } - } else if (event == ASSOC_REJECT) { - mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT); - } else { - handleEvent(event, eventData); } - mRecvErrors = 0; } } - private boolean connectToSupplicant() { - int connectTries = 0; + /* @return true if the event was supplicant disconnection */ + private boolean dispatchEvent(String eventStr) { + + if (!eventStr.startsWith(EVENT_PREFIX_STR)) { + if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && + 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { + mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); + } else if (eventStr.startsWith(WPS_SUCCESS_STR)) { + mStateMachine.sendMessage(WPS_SUCCESS_EVENT); + } else if (eventStr.startsWith(WPS_FAIL_STR)) { + handleWpsFailEvent(eventStr); + } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { + mStateMachine.sendMessage(WPS_OVERLAP_EVENT); + } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { + mStateMachine.sendMessage(WPS_TIMEOUT_EVENT); + } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { + handleP2pEvents(eventStr); + } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { + handleHostApEvents(eventStr); + } + else { + if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr); + } + return false; + } - while (true) { - if (mWifiNative.connectToSupplicant()) { - return true; + String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); + int nameEnd = eventName.indexOf(' '); + if (nameEnd != -1) + eventName = eventName.substring(0, nameEnd); + if (eventName.length() == 0) { + if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name"); + return false; + } + /* + * Map event name into event enum + */ + int event; + if (eventName.equals(CONNECTED_STR)) + event = CONNECTED; + else if (eventName.equals(DISCONNECTED_STR)) + event = DISCONNECTED; + else if (eventName.equals(STATE_CHANGE_STR)) + event = STATE_CHANGE; + else if (eventName.equals(SCAN_RESULTS_STR)) + event = SCAN_RESULTS; + else if (eventName.equals(LINK_SPEED_STR)) + event = LINK_SPEED; + else if (eventName.equals(TERMINATING_STR)) + event = TERMINATING; + else if (eventName.equals(DRIVER_STATE_STR)) + event = DRIVER_STATE; + else if (eventName.equals(EAP_FAILURE_STR)) + event = EAP_FAILURE; + else if (eventName.equals(ASSOC_REJECT_STR)) + event = ASSOC_REJECT; + else + event = UNKNOWN; + + String eventData = eventStr; + if (event == DRIVER_STATE || event == LINK_SPEED) + eventData = eventData.split(" ")[1]; + else if (event == STATE_CHANGE || event == EAP_FAILURE) { + int ind = eventStr.indexOf(" "); + if (ind != -1) { + eventData = eventStr.substring(ind + 1); } - if (connectTries++ < 5) { - nap(1); - } else { - break; + } else { + int ind = eventStr.indexOf(" - "); + if (ind != -1) { + eventData = eventStr.substring(ind + 3); + } + } + + if (event == STATE_CHANGE) { + handleSupplicantStateChange(eventData); + } else if (event == DRIVER_STATE) { + handleDriverEvent(eventData); + } else if (event == TERMINATING) { + /** + * Close the supplicant connection if we see + * too many recv errors + */ + if (eventData.startsWith(WPA_RECV_ERROR_STR)) { + if (++mRecvErrors > MAX_RECV_ERRORS) { + if (DBG) { + Log.d(TAG, "too many recv errors, closing connection"); + } + } else { + return false; + } + } + + // notify and exit + mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + return true; + } else if (event == EAP_FAILURE) { + if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { + mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); } + } else if (event == ASSOC_REJECT) { + mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT); + } else { + handleEvent(event, eventData); } + mRecvErrors = 0; return false; } @@ -723,71 +884,60 @@ public class WifiMonitor { } notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState); } - } - private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { - String BSSID = null; - int networkId = -1; - if (newState == NetworkInfo.DetailedState.CONNECTED) { - Matcher match = mConnectedEventPattern.matcher(data); - if (!match.find()) { - if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); - } else { - BSSID = match.group(1); - try { - networkId = Integer.parseInt(match.group(2)); - } catch (NumberFormatException e) { - networkId = -1; + private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { + String BSSID = null; + int networkId = -1; + if (newState == NetworkInfo.DetailedState.CONNECTED) { + Matcher match = mConnectedEventPattern.matcher(data); + if (!match.find()) { + if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); + } else { + BSSID = match.group(1); + try { + networkId = Integer.parseInt(match.group(2)); + } catch (NumberFormatException e) { + networkId = -1; + } } + notifyNetworkStateChange(newState, BSSID, networkId); } } - notifyNetworkStateChange(newState, BSSID, networkId); - } - /** - * Send the state machine a notification that the state of Wifi connectivity - * has changed. - * @param networkId the configured network on which the state change occurred - * @param newState the new network state - * @param BSSID when the new state is {@link DetailedState#CONNECTED - * NetworkInfo.DetailedState.CONNECTED}, - * this is the MAC address of the access point. Otherwise, it - * is {@code null}. - */ - void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { - if (newState == NetworkInfo.DetailedState.CONNECTED) { - Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, - netId, 0, BSSID); - mStateMachine.sendMessage(m); - } else { - Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, - netId, 0, BSSID); - mStateMachine.sendMessage(m); + /** + * Send the state machine a notification that the state of Wifi connectivity + * has changed. + * @param networkId the configured network on which the state change occurred + * @param newState the new network state + * @param BSSID when the new state is {@link DetailedState#CONNECTED + * NetworkInfo.DetailedState.CONNECTED}, + * this is the MAC address of the access point. Otherwise, it + * is {@code null}. + */ + void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { + if (newState == NetworkInfo.DetailedState.CONNECTED) { + Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, + netId, 0, BSSID); + mStateMachine.sendMessage(m); + } else { + Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, + netId, 0, BSSID); + mStateMachine.sendMessage(m); + } } - } - /** - * Send the state machine a notification that the state of the supplicant - * has changed. - * @param networkId the configured network on which the state change occurred - * @param wifiSsid network name - * @param BSSID network address - * @param newState the new {@code SupplicantState} - */ - void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID, - SupplicantState newState) { - mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, - new StateChangeResult(networkId, wifiSsid, BSSID, newState))); - } - - /** - * Sleep for a period of time. - * @param secs the number of seconds to sleep - */ - private static void nap(int secs) { - try { - Thread.sleep(secs * 1000); - } catch (InterruptedException ignore) { + /** + * Send the state machine a notification that the state of the supplicant + * has changed. + * @param networkId the configured network on which the state change occurred + * @param wifiSsid network name + * @param BSSID network address + * @param newState the new {@code SupplicantState} + */ + void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID, + SupplicantState newState) { + mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, + new StateChangeResult(networkId, wifiSsid, BSSID, newState))); } } } diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index b1dd2ce..d30c7cf 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -47,7 +47,9 @@ public class WifiNative { static final int SCAN_WITHOUT_CONNECTION_SETUP = 1; static final int SCAN_WITH_CONNECTION_SETUP = 2; - String mInterface = ""; + public final String mInterfaceName; + public final String mInterfacePrefix; + private boolean mSuspendOptEnabled = false; public native static boolean loadDriver(); @@ -62,52 +64,53 @@ public class WifiNative { or when the supplicant is hung */ public native static boolean killSupplicant(boolean p2pSupported); - private native boolean connectToSupplicant(String iface); + private native boolean connectToSupplicantNative(); - private native void closeSupplicantConnection(String iface); + private native void closeSupplicantConnectionNative(); /** * Wait for the supplicant to send an event, returning the event string. * @return the event string sent by the supplicant. */ - private native String waitForEvent(String iface); + private native String waitForEventNative(); - private native boolean doBooleanCommand(String iface, String command); + private native boolean doBooleanCommandNative(String command); - private native int doIntCommand(String iface, String command); + private native int doIntCommandNative(String command); - private native String doStringCommand(String iface, String command); + private native String doStringCommandNative(String command); - public WifiNative(String iface) { - mInterface = iface; - mTAG = "WifiNative-" + iface; + public WifiNative(String interfaceName) { + mInterfaceName = interfaceName; + mInterfacePrefix = "IFNAME=" + interfaceName + " "; + mTAG = "WifiNative-" + interfaceName; } public boolean connectToSupplicant() { - return connectToSupplicant(mInterface); + return connectToSupplicantNative(); } public void closeSupplicantConnection() { - closeSupplicantConnection(mInterface); + closeSupplicantConnectionNative(); } public String waitForEvent() { - return waitForEvent(mInterface); + return waitForEventNative(); } private boolean doBooleanCommand(String command) { if (DBG) Log.d(mTAG, "doBoolean: " + command); - return doBooleanCommand(mInterface, command); + return doBooleanCommandNative(mInterfacePrefix + command); } private int doIntCommand(String command) { if (DBG) Log.d(mTAG, "doInt: " + command); - return doIntCommand(mInterface, command); + return doIntCommandNative(mInterfacePrefix + command); } private String doStringCommand(String command) { if (DBG) Log.d(mTAG, "doString: " + command); - return doStringCommand(mInterface, command); + return doStringCommandNative(mInterfacePrefix + command); } public boolean ping() { @@ -411,9 +414,9 @@ public class WifiNative { public boolean startWpsPbc(String iface, String bssid) { if (TextUtils.isEmpty(bssid)) { - return doBooleanCommand("IFNAME=" + iface + " WPS_PBC"); + return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC"); } else { - return doBooleanCommand("IFNAME=" + iface + " WPS_PBC " + bssid); + return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid); } } @@ -424,7 +427,7 @@ public class WifiNative { public boolean startWpsPinKeypad(String iface, String pin) { if (TextUtils.isEmpty(pin)) return false; - return doBooleanCommand("IFNAME=" + iface + " WPS_PIN any " + pin); + return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin); } @@ -438,9 +441,9 @@ public class WifiNative { public String startWpsPinDisplay(String iface, String bssid) { if (TextUtils.isEmpty(bssid)) { - return doStringCommand("IFNAME=" + iface + " WPS_PIN any"); + return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any"); } else { - return doStringCommand("IFNAME=" + iface + " WPS_PIN " + bssid); + return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid); } } @@ -492,7 +495,7 @@ public class WifiNative { } public boolean setP2pGroupIdle(String iface, int time) { - return doBooleanCommand("IFNAME=" + iface + " SET p2p_group_idle " + time); + return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time); } public void setPowerSave(boolean enabled) { @@ -505,9 +508,9 @@ public class WifiNative { public boolean setP2pPowerSave(String iface, boolean enabled) { if (enabled) { - return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 1"); + return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1"); } else { - return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 0"); + return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0"); } } @@ -645,7 +648,7 @@ public class WifiNative { public boolean p2pGroupRemove(String iface) { if (TextUtils.isEmpty(iface)) return false; - return doBooleanCommand("P2P_GROUP_REMOVE " + iface); + return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface); } public boolean p2pReject(String deviceAddress) { diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 4628c91..1fcd609 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -68,6 +68,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; +import android.util.Log; import android.util.LruCache; import android.text.TextUtils; @@ -543,7 +544,6 @@ public class WifiStateMachine extends StateMachine { public WifiStateMachine(Context context, String wlanInterface) { super("WifiStateMachine"); - mContext = context; mInterfaceName = wlanInterface; @@ -888,6 +888,7 @@ public class WifiStateMachine extends StateMachine { * TODO: doc */ public void setOperationalMode(int mode) { + if (DBG) log("setting operational mode to " + String.valueOf(mode)); sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); } @@ -1756,8 +1757,7 @@ public class WifiStateMachine extends StateMachine { /* Socket connection can be lost when we do a graceful shutdown * or when the driver is hung. Ensure supplicant is stopped here. */ - mWifiNative.killSupplicant(mP2pSupported); - mWifiNative.closeSupplicantConnection(); + mWifiMonitor.killSupplicant(mP2pSupported); sendSupplicantConnectionChangedBroadcast(false); setWifiState(WIFI_STATE_DISABLED); } @@ -2139,7 +2139,7 @@ public class WifiStateMachine extends StateMachine { * Avoids issues with drivers that do not handle interface down * on a running supplicant properly. */ - mWifiNative.killSupplicant(mP2pSupported); + mWifiMonitor.killSupplicant(mP2pSupported); if(mWifiNative.startSupplicant(mP2pSupported)) { setWifiState(WIFI_STATE_ENABLING); if (DBG) log("Supplicant start successful"); @@ -2222,7 +2222,7 @@ public class WifiStateMachine extends StateMachine { case WifiMonitor.SUP_DISCONNECTION_EVENT: if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { loge("Failed to setup control channel, restart supplicant"); - mWifiNative.killSupplicant(mP2pSupported); + mWifiMonitor.killSupplicant(mP2pSupported); transitionTo(mInitialState); sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); } else { @@ -2329,9 +2329,7 @@ public class WifiStateMachine extends StateMachine { } if (DBG) log("stopping supplicant"); - if (!mWifiNative.stopSupplicant()) { - loge("Failed to stop supplicant"); - } + mWifiMonitor.stopSupplicant(); /* Send ourselves a delayed message to indicate failure after a wait time */ sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, @@ -3200,6 +3198,7 @@ public class WifiStateMachine extends StateMachine { class VerifyingLinkState extends State { @Override public void enter() { + log(getName() + " enter"); setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); sendNetworkStateChangeBroadcast(mLastBssid); @@ -3209,11 +3208,14 @@ public class WifiStateMachine extends StateMachine { switch (message.what) { case WifiWatchdogStateMachine.POOR_LINK_DETECTED: //stay here + log(getName() + " POOR_LINK_DETECTED: no transition"); break; case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: + log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); transitionTo(mCaptivePortalCheckState); break; default: + log(getName() + " what=" + message.what + " NOT_HANDLED"); return NOT_HANDLED; } return HANDLED; @@ -3223,6 +3225,7 @@ public class WifiStateMachine extends StateMachine { class CaptivePortalCheckState extends State { @Override public void enter() { + log(getName() + " enter"); setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK); sendNetworkStateChangeBroadcast(mLastBssid); @@ -3231,6 +3234,7 @@ public class WifiStateMachine extends StateMachine { public boolean processMessage(Message message) { switch (message.what) { case CMD_CAPTIVE_CHECK_COMPLETE: + log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE"); try { mNwService.enableIpv6(mInterfaceName); } catch (RemoteException re) { diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index cf75381..461dedb 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -120,6 +120,11 @@ public class WifiStateTracker implements NetworkStateTracker { mWifiManager.captivePortalCheckComplete(); } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Turn the wireless radio off for a network. * @param turnOn {@code true} to turn the radio on, {@code false} diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 68a082a..63b94a2 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -858,7 +858,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast(); - mWifiNative.closeSupplicantConnection(); + mWifiMonitor.stopMonitoring(); transitionTo(mP2pDisablingState); break; case WifiP2pManager.SET_DEVICE_NAME: |
