summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/GoogleLocationSettingManager.java156
-rw-r--r--core/java/android/content/AbstractThreadedSyncAdapter.java9
-rwxr-xr-xcore/java/android/webkit/GeolocationPermissions.java63
-rw-r--r--core/java/android/webkit/WebSettings.java8
-rw-r--r--include/media/stagefright/OMXCodec.h1
-rw-r--r--media/libstagefright/OMXCodec.cpp50
-rw-r--r--services/java/com/android/server/LocationManagerService.java31
7 files changed, 300 insertions, 18 deletions
diff --git a/core/java/android/GoogleLocationSettingManager.java b/core/java/android/GoogleLocationSettingManager.java
new file mode 100644
index 000000000000..fe7fce6b88b7
--- /dev/null
+++ b/core/java/android/GoogleLocationSettingManager.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 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.webkit;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+
+import java.util.HashSet;
+
+/**
+ * A class to manage the interaction between the system setting 'Location &
+ * Security - Share with Google' and the browser. When this setting is set
+ * to true, we allow Geolocation for Google origins. When this setting is
+ * set to false, we clear Geolocation permissions for Google origins.
+ * @hide pending API council review
+ */
+class GoogleLocationSettingManager {
+ // The application context.
+ private Context mContext;
+ // The observer used to listen to the system setting.
+ private GoogleLocationSettingObserver mSettingObserver;
+
+ // The value of the system setting that indicates true.
+ private final static int sSystemSettingTrue = 1;
+ // The value of the system setting that indicates false.
+ private final static int sSystemSettingFalse = 0;
+ // The value of the USE_LOCATION_FOR_SERVICES system setting last read
+ // by the browser.
+ private final static String LAST_READ_USE_LOCATION_FOR_SERVICES =
+ "lastReadUseLocationForServices";
+ // The Google origins we consider.
+ private static HashSet<String> sGoogleOrigins;
+ static {
+ sGoogleOrigins = new HashSet<String>();
+ // NOTE: DO NOT ADD A "/" AT THE END!
+ sGoogleOrigins.add("http://www.google.com");
+ sGoogleOrigins.add("http://www.google.co.uk");
+ }
+
+ GoogleLocationSettingManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Starts the manager. Checks whether the setting has changed and
+ * installs an observer to listen for future changes.
+ */
+ public void start() {
+ maybeApplySetting();
+
+ mSettingObserver = new GoogleLocationSettingObserver();
+ mSettingObserver.observe();
+ }
+
+ /**
+ * Checks to see if the system setting has changed and if so,
+ * updates the Geolocation permissions accordingly.
+ */
+ private void maybeApplySetting() {
+ int setting = getSystemSetting();
+ if (settingChanged(setting)) {
+ applySetting(setting);
+ }
+ }
+
+ /**
+ * Gets the current system setting for 'Use location for Google services'.
+ * @return The system setting.
+ */
+ private int getSystemSetting() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.USE_LOCATION_FOR_SERVICES,
+ sSystemSettingFalse);
+ }
+
+ /**
+ * Determines whether the supplied setting has changed from the last
+ * value read by the browser.
+ * @param setting The setting.
+ * @return Whether the setting has changed from the last value read
+ * by the browser.
+ */
+ private boolean settingChanged(int setting) {
+ SharedPreferences preferences =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
+ // Default to false. If the system setting is false the first time it is ever read by the
+ // browser, there's nothing to do.
+ int lastReadSetting = sSystemSettingFalse;
+ lastReadSetting = preferences.getInt(LAST_READ_USE_LOCATION_FOR_SERVICES,
+ lastReadSetting);
+
+ if (lastReadSetting == setting) {
+ return false;
+ }
+
+ Editor editor = preferences.edit();
+ editor.putInt(LAST_READ_USE_LOCATION_FOR_SERVICES, setting);
+ editor.commit();
+ return true;
+ }
+
+ /**
+ * Applies the supplied setting to the Geolocation permissions.
+ * @param setting The setting.
+ */
+ private void applySetting(int setting) {
+ for (String origin : sGoogleOrigins) {
+ if (setting == sSystemSettingTrue) {
+ GeolocationPermissions.getInstance().allow(origin);
+ } else {
+ GeolocationPermissions.getInstance().clear(origin);
+ }
+ }
+ }
+
+ /**
+ * This class implements an observer to listen for changes to the
+ * system setting.
+ */
+ class GoogleLocationSettingObserver extends ContentObserver {
+ GoogleLocationSettingObserver() {
+ super(new Handler());
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ maybeApplySetting();
+ }
+ }
+}
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 424cb190e0f8..b01fc08defff 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -39,8 +39,9 @@ public abstract class AbstractThreadedSyncAdapter {
private final AtomicInteger mNumSyncStarts;
private final ISyncAdapterImpl mISyncAdapterImpl;
- // all accesses to this member variable must be synchronized on "this"
+ // all accesses to this member variable must be synchronized on mSyncThreadLock
private SyncThread mSyncThread;
+ private final Object mSyncThreadLock = new Object();
/** Kernel event log tag. Also listed in data/etc/event-log-tags. */
public static final int LOG_SYNC_DETAILS = 2743;
@@ -71,7 +72,7 @@ public abstract class AbstractThreadedSyncAdapter {
boolean alreadyInProgress;
// synchronize to make sure that mSyncThread doesn't change between when we
// check it and when we use it
- synchronized (this) {
+ synchronized (mSyncThreadLock) {
if (mSyncThread == null) {
if (mAutoInitialize
&& extras != null
@@ -102,7 +103,7 @@ public abstract class AbstractThreadedSyncAdapter {
public void cancelSync(ISyncContext syncContext) {
// synchronize to make sure that mSyncThread doesn't change between when we
// check it and when we use it
- synchronized (this) {
+ synchronized (mSyncThreadLock) {
if (mSyncThread != null
&& mSyncThread.mSyncContext.getISyncContext() == syncContext) {
mSyncThread.interrupt();
@@ -158,7 +159,7 @@ public abstract class AbstractThreadedSyncAdapter {
}
// synchronize so that the assignment will be seen by other threads
// that also synchronize accesses to mSyncThread
- synchronized (this) {
+ synchronized (mSyncThreadLock) {
mSyncThread = null;
}
}
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index d06d7e2e9f0f..e985ccce6831 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -22,6 +22,7 @@ import android.util.Log;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashSet;
import java.util.Set;
@@ -50,6 +51,8 @@ public final class GeolocationPermissions {
// Members used to transfer the origins and permissions between threads.
private Set<String> mOrigins;
private boolean mAllowed;
+ private Set<String> mOriginsToClear;
+ private Set<String> mOriginsToAllow;
private static Lock mLock = new ReentrantLock();
private static boolean mUpdated;
private static Condition mUpdatedCondition = mLock.newCondition();
@@ -58,7 +61,8 @@ public final class GeolocationPermissions {
static final int GET_ORIGINS = 0;
static final int GET_ALLOWED = 1;
static final int CLEAR = 2;
- static final int CLEAR_ALL = 3;
+ static final int ALLOW = 3;
+ static final int CLEAR_ALL = 4;
/**
* Gets the singleton instance of the class.
@@ -74,6 +78,7 @@ public final class GeolocationPermissions {
* Creates the message handler. Must be called on the WebKit thread.
*/
public void createHandler() {
+ mLock.lock();
if (mHandler == null) {
mHandler = new Handler() {
@Override
@@ -89,13 +94,28 @@ public final class GeolocationPermissions {
case CLEAR:
nativeClear((String) msg.obj);
break;
+ case ALLOW:
+ nativeAllow((String) msg.obj);
+ break;
case CLEAR_ALL:
nativeClearAll();
break;
}
}
};
+
+ if (mOriginsToClear != null) {
+ for (String origin : mOriginsToClear) {
+ nativeClear(origin);
+ }
+ }
+ if (mOriginsToAllow != null) {
+ for (String origin : mOriginsToAllow) {
+ nativeAllow(origin);
+ }
+ }
}
+ mLock.unlock();
}
/**
@@ -179,11 +199,47 @@ public final class GeolocationPermissions {
}
/**
- * Clears the permission state for the specified origin.
+ * Clears the permission state for the specified origin. This method may be
+ * called before the WebKit thread has intialized the message handler.
+ * Messages will be queued until this time.
*/
public void clear(String origin) {
// Called on the UI thread.
- postMessage(Message.obtain(null, CLEAR, origin));
+ mLock.lock();
+ if (mHandler == null) {
+ if (mOriginsToClear == null) {
+ mOriginsToClear = new HashSet<String>();
+ }
+ mOriginsToClear.add(origin);
+ if (mOriginsToAllow != null) {
+ mOriginsToAllow.remove(origin);
+ }
+ } else {
+ postMessage(Message.obtain(null, CLEAR, origin));
+ }
+ mLock.unlock();
+ }
+
+ /**
+ * Allows the specified origin. This method may be called before the WebKit
+ * thread has intialized the message handler. Messages will be queued until
+ * this time.
+ */
+ public void allow(String origin) {
+ // Called on the UI thread.
+ mLock.lock();
+ if (mHandler == null) {
+ if (mOriginsToAllow == null) {
+ mOriginsToAllow = new HashSet<String>();
+ }
+ mOriginsToAllow.add(origin);
+ if (mOriginsToClear != null) {
+ mOriginsToClear.remove(origin);
+ }
+ } else {
+ postMessage(Message.obtain(null, ALLOW, origin));
+ }
+ mLock.unlock();
}
/**
@@ -198,5 +254,6 @@ public final class GeolocationPermissions {
private static native Set nativeGetOrigins();
private static native boolean nativeGetAllowed(String origin);
private static native void nativeClear(String origin);
+ private static native void nativeAllow(String origin);
private static native void nativeClearAll();
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index e8b2702f5bc5..050a88644965 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -167,7 +167,7 @@ public class WebSettings {
private boolean mDatabaseEnabled = false;
private boolean mDomStorageEnabled = false;
private boolean mWorkersEnabled = false; // only affects V8.
- private boolean mGeolocationEnabled = false;
+ private boolean mGeolocationEnabled = true;
// HTML5 configuration parameters
private long mAppCacheMaxSize = Long.MAX_VALUE;
private String mAppCachePath = "";
@@ -189,6 +189,10 @@ public class WebSettings {
private boolean mAllowFileAccess = true;
private boolean mLoadWithOverviewMode = true;
+ // Manages interaction of the system setting 'Location & security - Share
+ // with Google' and the browser.
+ static GoogleLocationSettingManager sGoogleLocationSettingManager;
+
// Class to handle messages before WebCore is ready.
private class EventHandler {
// Message id for syncing
@@ -1315,6 +1319,8 @@ public class WebSettings {
if (DebugFlags.WEB_SETTINGS) {
junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
}
+ sGoogleLocationSettingManager = new GoogleLocationSettingManager(mContext);
+ sGoogleLocationSettingManager.start();
nativeSync(frame.mNativeFrame);
mSyncPending = false;
mEventHandler.createHandler();
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index ff94e1000198..08d550c8f4b7 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -84,6 +84,7 @@ private:
kRequiresAllocateBufferOnInputPorts = 8,
kRequiresFlushCompleteEmulation = 16,
kRequiresAllocateBufferOnOutputPorts = 32,
+ kRequiresFlushBeforeShutdown = 64,
};
struct BufferInfo {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index cdaba7c923a9..90ebd7e1feca 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -194,6 +194,11 @@ sp<OMXCodec> OMXCodec::Create(
if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
quirks |= kNeedsFlushBeforeDisable;
quirks |= kRequiresFlushCompleteEmulation;
+
+ // The following is currently necessary for proper shutdown
+ // behaviour, but NOT enabled by default in order to make the
+ // bug reproducible...
+ // quirks |= kRequiresFlushBeforeShutdown;
}
if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
quirks |= kRequiresLoadedToIdleAfterAllocation;
@@ -1015,6 +1020,19 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
CHECK_EQ(portIndex, kPortIndexOutput);
disablePortAsync(portIndex);
+ } else if (mState == EXECUTING_TO_IDLE) {
+ if (mPortStatus[kPortIndexInput] == ENABLED
+ && mPortStatus[kPortIndexOutput] == ENABLED) {
+ LOGV("Finished flushing both ports, now completing "
+ "transition from EXECUTING to IDLE.");
+
+ mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+ mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+ }
} else {
// We're flushing both ports in preparation for seeking.
@@ -1180,7 +1198,8 @@ void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
}
bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
- CHECK(mState == EXECUTING || mState == RECONFIGURING);
+ CHECK(mState == EXECUTING || mState == RECONFIGURING
+ || mState == EXECUTING_TO_IDLE);
LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
@@ -1625,12 +1644,31 @@ status_t OMXCodec::stop() {
{
setState(EXECUTING_TO_IDLE);
- mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
- mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+ if (mQuirks & kRequiresFlushBeforeShutdown) {
+ LOGV("This component requires a flush before transitioning "
+ "from EXECUTING to IDLE...");
- status_t err =
- mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
- CHECK_EQ(err, OK);
+ bool emulateInputFlushCompletion =
+ !flushPortAsync(kPortIndexInput);
+
+ bool emulateOutputFlushCompletion =
+ !flushPortAsync(kPortIndexOutput);
+
+ if (emulateInputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+ }
+
+ if (emulateOutputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+ }
+ } else {
+ mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+ mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+ }
while (mState != LOADED && mState != ERROR) {
mAsyncCompletion.wait(mLock);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 2201b55beaa2..c65c2beb397d 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -120,6 +120,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private IGpsStatusProvider mGpsStatusProvider;
private LocationWorkerHandler mLocationHandler;
+ // Cache the real providers for use in addTestProvider() and removeTestProvider()
+ LocationProviderProxy mNetworkLocationProvider;
+ LocationProviderProxy mGpsLocationProvider;
+
// Handler messages
private static final int MESSAGE_LOCATION_CHANGED = 1;
@@ -539,6 +543,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mGpsStatusProvider = provider.getGpsStatusProvider();
LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
addProvider(proxy);
+ mGpsLocationProvider = proxy;
}
updateProvidersLocked();
@@ -616,6 +621,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
addProvider(proxy);
updateProvidersLocked();
+ if (LocationManager.NETWORK_PROVIDER.equals(name)) {
+ mNetworkLocationProvider = proxy;
+ }
// notify provider of current network state
proxy.updateNetworkState(mNetworkState);
@@ -1794,16 +1802,22 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
requiresNetwork, requiresSatellite,
requiresCell, hasMonetaryCost, supportsAltitude,
supportsSpeed, supportsBearing, powerRequirement, accuracy);
+ // remove the real provider if we are replacing GPS or network provider
+ if (LocationManager.GPS_PROVIDER.equals(name)
+ || LocationManager.NETWORK_PROVIDER.equals(name)) {
+ LocationProviderProxy proxy = mProvidersByName.get(name);
+ if (proxy != null) {
+ proxy.enableLocationTracking(false);
+ removeProvider(proxy);
+ }
+ }
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
-
- // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
- long identity = Binder.clearCallingIdentity();
addProvider(new LocationProviderProxy(name, provider));
mMockProviders.put(name, provider);
+ mLastKnownLocation.put(name, null);
updateProvidersLocked();
- Binder.restoreCallingIdentity(identity);
}
}
@@ -1816,6 +1830,15 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
removeProvider(mProvidersByName.get(provider));
mMockProviders.remove(mockProvider);
+ // reinstall real provider if we were mocking GPS or network provider
+ if (LocationManager.GPS_PROVIDER.equals(provider) &&
+ mGpsLocationProvider != null) {
+ addProvider(mGpsLocationProvider);
+ } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
+ mNetworkLocationProvider != null) {
+ addProvider(mNetworkLocationProvider);
+ }
+ mLastKnownLocation.put(provider, null);
updateProvidersLocked();
}
}