Merge "new accessibility section" into jb-dev
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 96a6438..a509156 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -1056,7 +1056,12 @@
rc = -errno;
goto out;
}
-
+ if (chmod(libdir, 0755) < 0) {
+ ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ rc = -errno;
+ goto out;
+ }
if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
unlink(libdir);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b902550..411f6d0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -361,10 +361,10 @@
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
}});
- registerService(LOCATION_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
+ registerService(LOCATION_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(LOCATION_SERVICE);
- return new LocationManager(ILocationManager.Stub.asInterface(b));
+ return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
}});
registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index 06b63a0c..99ab9cb 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -1,4 +1,6 @@
-page.title=Android 4.1 API Overview
+page.title=Android 4.0 Platform
+sdk.platform.version=4.0
+sdk.platform.apiLevel=14
@jd:body
<div id="qv-wrapper">
diff --git a/docs/html/design/media/actionbar_drawer.png b/docs/html/design/media/actionbar_drawer.png
new file mode 100644
index 0000000..95e04f5
--- /dev/null
+++ b/docs/html/design/media/actionbar_drawer.png
Binary files differ
diff --git a/docs/html/design/media/dialogs_popups_example.png b/docs/html/design/media/dialogs_popups_example.png
index 2deb00d..c7536f3 100644
--- a/docs/html/design/media/dialogs_popups_example.png
+++ b/docs/html/design/media/dialogs_popups_example.png
Binary files differ
diff --git a/docs/html/design/media/tabs_youtube.png b/docs/html/design/media/tabs_youtube.png
index 69e9268..31c626c 100644
--- a/docs/html/design/media/tabs_youtube.png
+++ b/docs/html/design/media/tabs_youtube.png
Binary files differ
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 21e8583..80aa77d 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -234,12 +234,7 @@
</div>
<div class="layout-content-col span-7">
-
- <img src="{@docRoot}design/media/action_bar_pattern_default_tabs.png">
- <div class="figure-caption">
- Default fixed tabs shown in Holo Dark & Light.
- </div>
-
+ <img src="{@docRoot}design/media/actionbar_drawer.png">
</div>
</div>
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 2255bf2..38a29d3 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -39,11 +39,11 @@
boolean providerMeetsCriteria(String provider, in Criteria criteria);
void requestLocationUpdates(String provider, in Criteria criteria, long minTime, float minDistance,
- boolean singleShot, in ILocationListener listener);
+ boolean singleShot, in ILocationListener listener, String packageName);
void requestLocationUpdatesPI(String provider, in Criteria criteria, long minTime, float minDistance,
- boolean singleShot, in PendingIntent intent);
- void removeUpdates(in ILocationListener listener);
- void removeUpdatesPI(in PendingIntent intent);
+ boolean singleShot, in PendingIntent intent, String packageName);
+ void removeUpdates(in ILocationListener listener, String packageName);
+ void removeUpdatesPI(in PendingIntent intent, String packageName);
boolean addGpsStatusListener(IGpsStatusListener listener);
void removeGpsStatusListener(IGpsStatusListener listener);
@@ -54,13 +54,13 @@
boolean sendExtraCommand(String provider, String command, inout Bundle extras);
void addProximityAlert(double latitude, double longitude, float distance,
- long expiration, in PendingIntent intent);
+ long expiration, in PendingIntent intent, String packageName);
void removeProximityAlert(in PendingIntent intent);
Bundle getProviderInfo(String provider);
boolean isProviderEnabled(String provider);
- Location getLastKnownLocation(String provider);
+ Location getLastKnownLocation(String provider, String packageName);
// Used by location providers to tell the location manager when it has a new location.
// Passive is true if the location is coming from the passive provider, in which case
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 1299574..5c256a3 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -17,6 +17,7 @@
package android.location;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
@@ -160,6 +161,8 @@
*/
public static final String EXTRA_GPS_ENABLED = "enabled";
+ private final Context mContext;
+
// Map from LocationListeners to their associated ListenerTransport objects
private HashMap<LocationListener,ListenerTransport> mListeners =
new HashMap<LocationListener,ListenerTransport>();
@@ -260,8 +263,9 @@
* right way to create an instance of this class is using the
* factory Context.getSystemService.
*/
- public LocationManager(ILocationManager service) {
+ public LocationManager(Context context, ILocationManager service) {
mService = service;
+ mContext = context;
}
private LocationProvider createProvider(String name, Bundle info) {
@@ -657,7 +661,8 @@
transport = new ListenerTransport(listener, looper);
}
mListeners.put(listener, transport);
- mService.requestLocationUpdates(provider, criteria, minTime, minDistance, singleShot, transport);
+ mService.requestLocationUpdates(provider, criteria, minTime, minDistance,
+ singleShot, transport, mContext.getPackageName());
}
} catch (RemoteException ex) {
Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
@@ -837,7 +842,8 @@
}
try {
- mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot, intent);
+ mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot,
+ intent, mContext.getPackageName());
} catch (RemoteException ex) {
Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
}
@@ -1005,7 +1011,7 @@
try {
ListenerTransport transport = mListeners.remove(listener);
if (transport != null) {
- mService.removeUpdates(transport);
+ mService.removeUpdates(transport, mContext.getPackageName());
}
} catch (RemoteException ex) {
Log.e(TAG, "removeUpdates: DeadObjectException", ex);
@@ -1028,7 +1034,7 @@
Log.d(TAG, "removeUpdates: intent = " + intent);
}
try {
- mService.removeUpdatesPI(intent);
+ mService.removeUpdatesPI(intent, mContext.getPackageName());
} catch (RemoteException ex) {
Log.e(TAG, "removeUpdates: RemoteException", ex);
}
@@ -1087,7 +1093,7 @@
}
try {
mService.addProximityAlert(latitude, longitude, radius,
- expiration, intent);
+ expiration, intent, mContext.getPackageName());
} catch (RemoteException ex) {
Log.e(TAG, "addProximityAlert: RemoteException", ex);
}
@@ -1153,7 +1159,7 @@
throw new IllegalArgumentException("provider==null");
}
try {
- return mService.getLastKnownLocation(provider);
+ return mService.getLastKnownLocation(provider, mContext.getPackageName());
} catch (RemoteException ex) {
Log.e(TAG, "getLastKnowLocation: RemoteException", ex);
return null;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 2918dbc..8c1581c 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -32,6 +32,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.database.Cursor;
import android.location.Address;
import android.location.Criteria;
@@ -79,6 +80,8 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
@@ -109,6 +112,9 @@
private static final String INSTALL_LOCATION_PROVIDER =
android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
+ private static final String BLACKLIST_CONFIG_NAME = "locationPackagePrefixBlacklist";
+ private static final String WHITELIST_CONFIG_NAME = "locationPackagePrefixWhitelist";
+
// Location Providers may sometimes deliver location updates
// slightly faster that requested - provide grace period so
// we don't unnecessarily filter events that are otherwise on
@@ -193,6 +199,10 @@
private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
+ // for prefix blacklist
+ private String[] mWhitelist = new String[0];
+ private String[] mBlacklist = new String[0];
+
// for Settings change notification
private ContentQueryMap mSettings;
@@ -205,20 +215,23 @@
final PendingIntent mPendingIntent;
final Object mKey;
final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
+ final String mPackageName;
int mPendingBroadcasts;
String mRequiredPermissions;
- Receiver(ILocationListener listener) {
+ Receiver(ILocationListener listener, String packageName) {
mListener = listener;
mPendingIntent = null;
mKey = listener.asBinder();
+ mPackageName = packageName;
}
- Receiver(PendingIntent intent) {
+ Receiver(PendingIntent intent, String packageName) {
mPendingIntent = intent;
mListener = null;
mKey = intent;
+ mPackageName = packageName;
}
@Override
@@ -601,6 +614,7 @@
// Load providers
loadProviders();
+ loadBlacklist();
// Register for Network (Wifi or Mobile) updates
IntentFilter intentFilter = new IntentFilter();
@@ -1110,11 +1124,11 @@
}
}
- private Receiver getReceiver(ILocationListener listener) {
+ private Receiver getReceiver(ILocationListener listener, String packageName) {
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver == null) {
- receiver = new Receiver(listener);
+ receiver = new Receiver(listener, packageName);
mReceivers.put(binder, receiver);
try {
@@ -1129,10 +1143,10 @@
return receiver;
}
- private Receiver getReceiver(PendingIntent intent) {
+ private Receiver getReceiver(PendingIntent intent, String packageName) {
Receiver receiver = mReceivers.get(intent);
if (receiver == null) {
- receiver = new Receiver(intent);
+ receiver = new Receiver(intent, packageName);
mReceivers.put(intent, receiver);
}
return receiver;
@@ -1157,7 +1171,9 @@
}
public void requestLocationUpdates(String provider, Criteria criteria,
- long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
+ long minTime, float minDistance, boolean singleShot, ILocationListener listener,
+ String packageName) {
+ checkPackageName(Binder.getCallingUid(), packageName);
if (criteria != null) {
// FIXME - should we consider using multiple providers simultaneously
// rather than only the best one?
@@ -1170,7 +1186,7 @@
try {
synchronized (mLock) {
requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
- getReceiver(listener));
+ getReceiver(listener, packageName));
}
} catch (SecurityException se) {
throw se;
@@ -1194,7 +1210,9 @@
}
public void requestLocationUpdatesPI(String provider, Criteria criteria,
- long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
+ long minTime, float minDistance, boolean singleShot, PendingIntent intent,
+ String packageName) {
+ checkPackageName(Binder.getCallingUid(), packageName);
validatePendingIntent(intent);
if (criteria != null) {
// FIXME - should we consider using multiple providers simultaneously
@@ -1208,7 +1226,7 @@
try {
synchronized (mLock) {
requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
- getReceiver(intent));
+ getReceiver(intent, packageName));
}
} catch (SecurityException se) {
throw se;
@@ -1270,10 +1288,10 @@
}
}
- public void removeUpdates(ILocationListener listener) {
+ public void removeUpdates(ILocationListener listener, String packageName) {
try {
synchronized (mLock) {
- removeUpdatesLocked(getReceiver(listener));
+ removeUpdatesLocked(getReceiver(listener, packageName));
}
} catch (SecurityException se) {
throw se;
@@ -1284,10 +1302,10 @@
}
}
- public void removeUpdatesPI(PendingIntent intent) {
+ public void removeUpdatesPI(PendingIntent intent, String packageName) {
try {
synchronized (mLock) {
- removeUpdatesLocked(getReceiver(intent));
+ removeUpdatesLocked(getReceiver(intent, packageName));
}
} catch (SecurityException se) {
throw se;
@@ -1446,15 +1464,17 @@
final long mExpiration;
final PendingIntent mIntent;
final Location mLocation;
+ final String mPackageName;
public ProximityAlert(int uid, double latitude, double longitude,
- float radius, long expiration, PendingIntent intent) {
+ float radius, long expiration, PendingIntent intent, String packageName) {
mUid = uid;
mLatitude = latitude;
mLongitude = longitude;
mRadius = radius;
mExpiration = expiration;
mIntent = intent;
+ mPackageName = packageName;
mLocation = new Location("");
mLocation.setLatitude(latitude);
@@ -1522,6 +1542,10 @@
PendingIntent intent = alert.getIntent();
long expiration = alert.getExpiration();
+ if (inBlacklist(alert.mPackageName)) {
+ continue;
+ }
+
if ((expiration == -1) || (now <= expiration)) {
boolean entered = mProximitiesEntered.contains(alert);
boolean inProximity =
@@ -1632,11 +1656,12 @@
}
public void addProximityAlert(double latitude, double longitude,
- float radius, long expiration, PendingIntent intent) {
+ float radius, long expiration, PendingIntent intent, String packageName) {
validatePendingIntent(intent);
try {
synchronized (mLock) {
- addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
+ addProximityAlertLocked(latitude, longitude, radius, expiration, intent,
+ packageName);
}
} catch (SecurityException se) {
throw se;
@@ -1648,7 +1673,7 @@
}
private void addProximityAlertLocked(double latitude, double longitude,
- float radius, long expiration, PendingIntent intent) {
+ float radius, long expiration, PendingIntent intent, String packageName) {
if (LOCAL_LOGV) {
Slog.v(TAG, "addProximityAlert: latitude = " + latitude +
", longitude = " + longitude +
@@ -1656,6 +1681,8 @@
", intent = " + intent);
}
+ checkPackageName(Binder.getCallingUid(), packageName);
+
// Require ability to access all providers for now
if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
!isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
@@ -1666,12 +1693,12 @@
expiration += System.currentTimeMillis();
}
ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
- latitude, longitude, radius, expiration, intent);
+ latitude, longitude, radius, expiration, intent, packageName);
mProximityAlerts.put(intent, alert);
if (mProximityReceiver == null) {
mProximityListener = new ProximityListener();
- mProximityReceiver = new Receiver(mProximityListener);
+ mProximityReceiver = new Receiver(mProximityListener, packageName);
for (int i = mProviders.size() - 1; i >= 0; i--) {
LocationProviderInterface provider = mProviders.get(i);
@@ -1787,13 +1814,13 @@
return isAllowedBySettingsLocked(provider);
}
- public Location getLastKnownLocation(String provider) {
+ public Location getLastKnownLocation(String provider, String packageName) {
if (LOCAL_LOGV) {
Slog.v(TAG, "getLastKnownLocation: " + provider);
}
try {
synchronized (mLock) {
- return _getLastKnownLocationLocked(provider);
+ return _getLastKnownLocationLocked(provider, packageName);
}
} catch (SecurityException se) {
throw se;
@@ -1803,8 +1830,9 @@
}
}
- private Location _getLastKnownLocationLocked(String provider) {
+ private Location _getLastKnownLocationLocked(String provider, String packageName) {
checkPermissionsSafe(provider, null);
+ checkPackageName(Binder.getCallingUid(), packageName);
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
@@ -1815,6 +1843,10 @@
return null;
}
+ if (inBlacklist(packageName)) {
+ return null;
+ }
+
return mLastKnownLocation.get(provider);
}
@@ -1877,6 +1909,10 @@
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
+ if (inBlacklist(receiver.mPackageName)) {
+ continue;
+ }
+
Location lastLoc = r.mLastFixBroadcast;
if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
if (lastLoc == null) {
@@ -2315,6 +2351,113 @@
}
}
+ public class BlacklistObserver extends ContentObserver {
+ public BlacklistObserver(Handler handler) {
+ super(handler);
+ }
+ @Override
+ public void onChange(boolean selfChange) {
+ reloadBlacklist();
+ }
+ }
+
+ private void loadBlacklist() {
+ // Register for changes
+ BlacklistObserver observer = new BlacklistObserver(mLocationHandler);
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ BLACKLIST_CONFIG_NAME), false, observer);
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ WHITELIST_CONFIG_NAME), false, observer);
+ reloadBlacklist();
+ }
+
+ private void reloadBlacklist() {
+ String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
+ String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
+ synchronized (mLock) {
+ mWhitelist = whitelist;
+ Slog.i(TAG, "whitelist: " + arrayToString(mWhitelist));
+ mBlacklist = blacklist;
+ Slog.i(TAG, "blacklist: " + arrayToString(mBlacklist));
+ }
+ }
+
+ private static String arrayToString(String[] array) {
+ StringBuilder s = new StringBuilder();
+ s.append('[');
+ boolean first = true;
+ for (String a : array) {
+ if (!first) s.append(',');
+ first = false;
+ s.append(a);
+ }
+ s.append(']');
+ return s.toString();
+ }
+
+ private String[] getStringArray(String key) {
+ String flatString = Settings.Secure.getString(mContext.getContentResolver(), key);
+ if (flatString == null) {
+ return new String[0];
+ }
+ String[] splitStrings = flatString.split(",");
+ ArrayList<String> result = new ArrayList<String>();
+ for (String pkg : splitStrings) {
+ pkg = pkg.trim();
+ if (pkg.isEmpty()) {
+ continue;
+ }
+ result.add(pkg);
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ /**
+ * Return true if in blacklist, and not in whitelist.
+ */
+ private boolean inBlacklist(String packageName) {
+ synchronized (mLock) {
+ for (String black : mBlacklist) {
+ if (packageName.startsWith(black)) {
+ if (inWhitelist(packageName)) {
+ continue;
+ } else {
+ if (LOCAL_LOGV) Log.d(TAG, "dropping location (blacklisted): "
+ + packageName + " matches " + black);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return true if any of packages are in whitelist
+ */
+ private boolean inWhitelist(String pkg) {
+ synchronized (mLock) {
+ for (String white : mWhitelist) {
+ if (pkg.startsWith(white)) return true;
+ }
+ }
+ return false;
+ }
+
+ private void checkPackageName(int uid, String packageName) {
+ if (packageName == null) {
+ throw new SecurityException("packageName cannot be null");
+ }
+ String[] packages = mPackageManager.getPackagesForUid(uid);
+ if (packages == null) {
+ throw new SecurityException("invalid UID " + uid);
+ }
+ for (String pkg : packages) {
+ if (packageName.equals(pkg)) return;
+ }
+ throw new SecurityException("invalid package name");
+ }
+
private void log(String log) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.d(TAG, log);
@@ -2346,6 +2489,8 @@
j.getValue().dump(pw, " ");
}
}
+ pw.println(" Package blacklist:" + arrayToString(mBlacklist));
+ pw.println(" Package whitelist:" + arrayToString(mWhitelist));
pw.println(" Records by Provider:");
for (Map.Entry<String, ArrayList<UpdateRecord>> i
: mRecordsByProvider.entrySet()) {