Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d875ce6d authored by Steve Block's avatar Steve Block
Browse files

Sets or clears Geolocation permissions for Google origins when the 'Location &...

Sets or clears Geolocation permissions for Google origins when the 'Location & privacy - Share with Google' sysetm setting is changed.

This fixes bug http://b/issue?id=1933893
parent 4804c3e2
Loading
Loading
Loading
Loading
+156 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }
}
+60 −3
Original line number Diff line number Diff line
@@ -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,12 +199,48 @@ 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.
        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();
    }

    /**
     * Clears the permission state for all origins.
@@ -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();
}
+6 −0
Original line number Diff line number Diff line
@@ -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();