OSDN Git Service

API for location settings injection
authorTom O'Neill <tomo@google.com>
Tue, 13 Aug 2013 21:41:22 +0000 (14:41 -0700)
committerTom O'Neill <tomo@google.com>
Tue, 13 Aug 2013 21:41:22 +0000 (14:41 -0700)
- Partial fix for b/10287745

Change-Id: Ie998ce0a7b350e4183fce5753bfac3eb51238ff4

api/current.txt
core/res/res/values/attrs.xml
location/java/android/location/SettingInjectorService.java [new file with mode: 0644]

index d79a8c0..75870ab 100644 (file)
@@ -11561,6 +11561,18 @@ package android.location {
     field public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
   }
 
+  public abstract class SettingInjectorService extends android.app.IntentService {
+    ctor public SettingInjectorService(java.lang.String);
+    method protected abstract android.location.SettingInjectorService.Status getStatus();
+    method protected final void onHandleIntent(android.content.Intent);
+  }
+
+  public static final class SettingInjectorService.Status {
+    ctor public SettingInjectorService.Status(java.lang.String, boolean);
+    field public final boolean enabled;
+    field public final java.lang.String summary;
+  }
+
 }
 
 package android.media {
index 721bc3f..03e9045 100644 (file)
     <declare-styleable name="SizeAdaptiveLayout" />
 
     <!-- =============================== -->
+    <!-- Location package class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <!-- Use <code>injected-location-setting</code> as the root tag of the XML resource that
+         describes an injected "Location services" setting. Note that the status value (subtitle)
+         for the setting is specified dynamically by a subclass of SettingInjectorService.
+     -->
+    <declare-styleable name="InjectedLocationSetting">
+        <!-- The user-visible name (title) of the setting. -->
+        <attr name="label"/>
+        <!-- The icon for the apps covered by the setting. Typically a generic icon for the
+             developer. -->
+        <attr name="icon"/>
+        <!-- The activity to launch when the setting is clicked on. -->
+        <attr name="settingsActivity"/>
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- LockPatternView class attributes -->
     <!-- =============================== -->
     <eat-comment />
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
new file mode 100644 (file)
index 0000000..d410408
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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.app.IntentService;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.preference.Preference;
+import android.util.Log;
+
+/**
+ * Dynamically specifies the summary (subtile) and enabled status of a preference injected into
+ * the "Settings > Location > Location services" list.
+ *
+ * The location services list is intended for use only by preferences that affect multiple apps from
+ * the same developer. Location settings that apply only to one app should be shown within that app,
+ * rather than in the system settings.
+ *
+ * To add a preference to the list, a subclass of {@link SettingInjectorService} must be declared in
+ * the manifest as so:
+ * <pre>
+ *     <service android:name="com.example.android.injector.MyInjectorService" >
+ *         <intent-filter>
+ *             <action android:name="com.android.settings.InjectedLocationSetting" />
+ *         </intent-filter>
+ *
+ *         <meta-data
+ *             android:name="com.android.settings.InjectedLocationSetting"
+ *             android:resource="@xml/my_injected_location_setting" />
+ *     </service>
+ * </pre>
+ * The resource file specifies the static data for the setting:
+ * <pre>
+ *     <injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+ *         android:label="@string/injected_setting_label"
+ *         android:icon="@drawable/ic_launcher"
+ *         android:settingsActivity="com.example.android.injector.MySettingActivity"
+ *     />
+ * </pre>
+ * Here:
+ * <ul>
+ *     <li>label: The {@link Preference#getTitle()} value. The title should make it clear which apps
+ *     are affected by the setting, typically by including the name of the developer. For example,
+ *     "Acme Corp. ads preferences." </li>
+ *
+ *     <li>icon: The {@link Preference#getIcon()} value. Typically this will be a generic icon for
+ *     the developer rather than the icon for an individual app.</li>
+ *
+ *     <li>settingsActivity: the activity which is launched to allow the user to modify the setting
+ *     value  The activity must be in the same package as the subclass of
+ *     {@link SettingInjectorService}. The activity should use your own branding to help emphasize
+ *     to the user that it is not part of the system settings.</li>
+ * </ul>
+ *
+ * For consistency, the label and {@link #getStatus()} values should be provided in all of the
+ * locales supported by the system settings app. The text should not contain offensive language.
+ *
+ * For compactness, only one copy of a given setting should be injected. If each account has a
+ * distinct value for the setting, then the {@link #getStatus()} value should represent a summary of
+ * the state across all of the accounts and {@code settingsActivity} should display the value for
+ * each account.
+ *
+ * Apps that violate these guidelines will be taken down from the Google Play Store and/or flagged
+ * as malware.
+ */
+// TODO: is there a public list of supported locales?
+// TODO: is there a public list of guidelines for settings text?
+public abstract class SettingInjectorService extends IntentService {
+
+    /**
+     * Name of the bundle key for the string specifying the status of the setting (e.g., "ON" or
+     * "OFF").
+     *
+     * @hide
+     */
+    public static final String STATUS_KEY = "status";
+
+    /**
+     * Name of the bundle key for the string specifying whether the setting is currently enabled.
+     *
+     * @hide
+     */
+    public static final String ENABLED_KEY = "enabled";
+
+    /**
+     * Name of the intent key used to specify the messenger
+     *
+     * @hide
+     */
+    public static final String MESSENGER_KEY = "messenger";
+
+    private final String mLogTag;
+
+    /**
+     * Constructor.
+     *
+     * @param logTag used for logging, must be less than 23 characters
+     */
+    public SettingInjectorService(String logTag) {
+        super(logTag);
+
+        // Fast fail if log tag is too long
+        Log.isLoggable(logTag, Log.WARN);
+
+        mLogTag = logTag;
+    }
+
+    @Override
+    final protected void onHandleIntent(Intent intent) {
+        // Get messenger first to ensure intent doesn't get messed with (in case we later decide
+        // to pass intent into getStatus())
+        Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY);
+
+        Status status = getStatus();
+
+        // Send the status back to the caller via the messenger
+        Message message = Message.obtain();
+        Bundle bundle = new Bundle();
+        bundle.putString(STATUS_KEY, status.summary);
+        bundle.putBoolean(ENABLED_KEY, status.enabled);
+        message.setData(bundle);
+
+        if (Log.isLoggable(mLogTag, Log.DEBUG)) {
+            Log.d(mLogTag,
+                    "received " + intent + " and " + status + ", sending message: " + message);
+        }
+        try {
+            messenger.send(message);
+        } catch (RemoteException e) {
+            Log.e(mLogTag, "", e);
+        }
+    }
+
+    /**
+     * Reads the status of the setting.
+     */
+    protected abstract Status getStatus();
+
+    /**
+     * Dynamic characteristics of an injected location setting.
+     */
+    public static final class Status {
+
+        public final String summary;
+
+        public final boolean enabled;
+
+        /**
+         * Constructor.
+         *
+         * @param summary the {@link Preference#getSummary()} value
+         * @param enabled the {@link Preference#isEnabled()} value
+         */
+        public Status(String summary, boolean enabled) {
+            this.summary = summary;
+            this.enabled = enabled;
+        }
+
+        @Override
+        public String toString() {
+            return "Status{summary='" + summary + '\'' + ", enabled=" + enabled + '}';
+        }
+    }
+}