android:scaleType="centerCrop"
android:src="@drawable/caption_background" />
- <com.android.settings.accessibility.CaptioningTextView
+ <com.android.internal.widget.SubtitleView
android:id="@+id/preview_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="96dp"
android:background="@drawable/transparency_tileable" >
- <com.android.settings.accessibility.CaptioningTextView
+ <com.android.internal.widget.SubtitleView
android:id="@+id/preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<item>true</item>
</string-array>
- <!-- Titles for debug overdraw preference. [CHAR LIMIT=35] -->
+ <!-- Titles for debug overdraw preference. [CHAR LIMIT=50] -->
<string-array name="debug_hw_overdraw_entries">
<item>Off</item>
<item>Show overdraw areas</item>
+ <item>Show areas for Deuteranomaly</item>
<item>Show overdraw counter</item>
</string-array>
<string-array name="debug_hw_overdraw_values" translatable="false" >
<item>false</item>
<item>show</item>
+ <item>show_deuteranomaly</item>
<item>count</item>
</string-array>
private void writeExperimentalWebViewOptions() {
if (mExperimentalWebView != null) {
+ if (!WebViewFactory.isUseExperimentalWebViewSet()) {
+ mEnableDialog = new AlertDialog.Builder(getActivity())
+ .setTitle("KLP WebView broke an app?")
+ .setMessage("Don't forget to raise a bug!\ngo/klp-webview-bug")
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setPositiveButton(android.R.string.ok, this)
+ .show();
+ }
WebViewFactory.setUseExperimentalWebView(mExperimentalWebView.isChecked());
pokeSystemProperties();
}
+++ /dev/null
-/*
- * 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.settings.accessibility;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources.Theme;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Join;
-import android.graphics.Paint.Style;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.text.Layout.Alignment;
-import android.text.StaticLayout;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.accessibility.CaptioningManager.CaptionStyle;
-
-public class CaptioningTextView extends View {
- // Ratio of inner padding to font size.
- private static final float INNER_PADDING_RATIO = 0.125f;
-
- // Default style dimensions in dips.
- private static final float CORNER_RADIUS = 2.0f;
- private static final float OUTLINE_WIDTH = 2.0f;
- private static final float SHADOW_RADIUS = 2.0f;
- private static final float SHADOW_OFFSET_X = 2.0f;
- private static final float SHADOW_OFFSET_Y = 2.0f;
-
- // Styled dimensions.
- private final float mCornerRadius;
- private final float mOutlineWidth;
- private final float mShadowRadius;
- private final float mShadowOffsetX;
- private final float mShadowOffsetY;
-
- /** Temporary rectangle used for computing line bounds. */
- private final RectF mLineBounds = new RectF();
-
- /** Temporary array used for computing line wrapping. */
- private float[] mTextWidths;
-
- /** Reusable string builder used for holding text. */
- private final StringBuilder mText = new StringBuilder();
- private final StringBuilder mBreakText = new StringBuilder();
-
- private TextPaint mPaint;
-
- private int mForegroundColor;
- private int mBackgroundColor;
- private int mEdgeColor;
- private int mEdgeType;
-
- private boolean mHasMeasurements;
- private int mLastMeasuredWidth;
- private StaticLayout mLayout;
-
- private float mSpacingMult = 1;
- private float mSpacingAdd = 0;
- private int mInnerPaddingX = 0;
-
- public CaptioningTextView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public CaptioningTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs);
-
- final Theme theme = context.getTheme();
- final TypedArray a = theme.obtainStyledAttributes(
- attrs, android.R.styleable.TextView, defStyle, 0);
-
- CharSequence text = "";
- int textSize = 15;
-
- final int n = a.getIndexCount();
- for (int i = 0; i < n; i++) {
- int attr = a.getIndex(i);
-
- switch (attr) {
- case android.R.styleable.TextView_text:
- text = a.getText(attr);
- break;
- case android.R.styleable.TextView_lineSpacingExtra:
- mSpacingAdd = a.getDimensionPixelSize(attr, (int) mSpacingAdd);
- break;
- case android.R.styleable.TextView_lineSpacingMultiplier:
- mSpacingMult = a.getFloat(attr, mSpacingMult);
- break;
- case android.R.styleable.TextAppearance_textSize:
- textSize = a.getDimensionPixelSize(attr, textSize);
- break;
- }
- }
-
- // Set up density-dependent properties.
- // TODO: Move these to a default style.
- final DisplayMetrics m = getContext().getResources().getDisplayMetrics();
- mCornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, m);
- mOutlineWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, OUTLINE_WIDTH, m);
- mShadowRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_RADIUS, m);
- mShadowOffsetX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_OFFSET_Y, m);
- mShadowOffsetY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_OFFSET_X, m);
-
- final TextPaint paint = new TextPaint();
- paint.setAntiAlias(true);
- paint.setSubpixelText(true);
-
- mPaint = paint;
-
- setText(text);
- setTextSize(textSize);
- }
-
- public void setText(int resId) {
- final CharSequence text = getContext().getText(resId);
- setText(text);
- }
-
- public void setText(CharSequence text) {
- mText.setLength(0);
- mText.append(text);
-
- mHasMeasurements = false;
-
- requestLayout();
- }
-
- public void setForegroundColor(int color) {
- mForegroundColor = color;
-
- invalidate();
- }
-
- @Override
- public void setBackgroundColor(int color) {
- mBackgroundColor = color;
-
- invalidate();
- }
-
- public void setEdgeType(int edgeType) {
- mEdgeType = edgeType;
-
- invalidate();
- }
-
- public void setEdgeColor(int color) {
- mEdgeColor = color;
-
- invalidate();
- }
-
- public void setTextSize(float size) {
- final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
- final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics);
- if (mPaint.getTextSize() != size) {
- mHasMeasurements = false;
- mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
- mPaint.setTextSize(size);
-
- requestLayout();
- }
- }
-
- public void setTypeface(Typeface typeface) {
- if (mPaint.getTypeface() != typeface) {
- mHasMeasurements = false;
- mPaint.setTypeface(typeface);
-
- requestLayout();
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int widthSpec = MeasureSpec.getSize(widthMeasureSpec);
-
- if (computeMeasurements(widthSpec)) {
- final StaticLayout layout = mLayout;
-
- // Account for padding.
- final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
- final int width = layout.getWidth() + paddingX;
- final int height = layout.getHeight() + mPaddingTop + mPaddingBottom;
- setMeasuredDimension(width, height);
- } else {
- setMeasuredDimension(MEASURED_STATE_TOO_SMALL, MEASURED_STATE_TOO_SMALL);
- }
- }
-
- @Override
- public void onLayout(boolean changed, int l, int t, int r, int b) {
- final int width = r - l;
-
- computeMeasurements(width);
- }
-
- private boolean computeMeasurements(int maxWidth) {
- if (mHasMeasurements && maxWidth == mLastMeasuredWidth) {
- return true;
- }
-
- // Account for padding.
- final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX;
- maxWidth -= paddingX;
-
- if (maxWidth <= 0) {
- return false;
- }
-
- final TextPaint paint = mPaint;
- final CharSequence text = mText;
- final int textLength = text.length();
- if (mTextWidths == null || mTextWidths.length < textLength) {
- mTextWidths = new float[textLength];
- }
-
- final float[] textWidths = mTextWidths;
- paint.getTextWidths(text, 0, textLength, textWidths);
-
- // Compute total length.
- float runLength = 0;
- for (int i = 0; i < textLength; i++) {
- runLength += textWidths[i];
- }
-
- final int lineCount = (int) (runLength / maxWidth) + 1;
- final int lineLength = (int) (runLength / lineCount);
-
- // Build line break buffer.
- final StringBuilder breakText = mBreakText;
- breakText.setLength(0);
-
- int line = 0;
- int lastBreak = 0;
- int maxRunLength = 0;
- runLength = 0;
- for (int i = 0; i < textLength; i++) {
- if (runLength > lineLength) {
- final CharSequence sequence = text.subSequence(lastBreak, i);
- final int trimmedLength = TextUtils.getTrimmedLength(sequence);
- breakText.append(sequence, 0, trimmedLength);
- breakText.append('\n');
- lastBreak = i;
- runLength = 0;
- }
-
- runLength += textWidths[i];
-
- if (runLength > maxRunLength) {
- maxRunLength = (int) Math.ceil(runLength);
- }
- }
- breakText.append(text.subSequence(lastBreak, textLength));
-
- mHasMeasurements = true;
- mLastMeasuredWidth = maxWidth;
-
- mLayout = new StaticLayout(breakText, paint, maxRunLength, Alignment.ALIGN_LEFT,
- mSpacingMult, mSpacingAdd, true);
-
- return true;
- }
-
- public void setStyle(int styleId) {
- final Context context = mContext;
- final ContentResolver cr = context.getContentResolver();
- final CaptionStyle style;
- if (styleId == CaptionStyle.PRESET_CUSTOM) {
- style = CaptionStyle.getCustomStyle(cr);
- } else {
- style = CaptionStyle.PRESETS[styleId];
- }
-
- mForegroundColor = style.foregroundColor;
- mBackgroundColor = style.backgroundColor;
- mEdgeType = style.edgeType;
- mEdgeColor = style.edgeColor;
- mHasMeasurements = false;
-
- final Typeface typeface = style.getTypeface();
- setTypeface(typeface);
-
- requestLayout();
- }
-
- @Override
- protected void onDraw(Canvas c) {
- final StaticLayout layout = mLayout;
- if (layout == null) {
- return;
- }
-
- final int saveCount = c.save();
- final int innerPaddingX = mInnerPaddingX;
- c.translate(mPaddingLeft + innerPaddingX, mPaddingTop);
-
- final RectF bounds = mLineBounds;
- final int lineCount = layout.getLineCount();
- final Paint paint = layout.getPaint();
- paint.setShadowLayer(0, 0, 0, 0);
-
- final int backgroundColor = mBackgroundColor;
- if (Color.alpha(backgroundColor) > 0) {
- paint.setColor(backgroundColor);
- paint.setStyle(Style.FILL);
-
- final float cornerRadius = mCornerRadius;
- float previousBottom = layout.getLineTop(0);
-
- for (int i = 0; i < lineCount; i++) {
- bounds.left = layout.getLineLeft(i) - innerPaddingX;
- bounds.right = layout.getLineRight(i) + innerPaddingX;
- bounds.top = previousBottom;
- bounds.bottom = layout.getLineBottom(i);
-
- previousBottom = bounds.bottom;
-
- c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
- }
- }
-
- final int edgeType = mEdgeType;
- if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
- paint.setColor(mEdgeColor);
- paint.setStyle(Style.FILL_AND_STROKE);
- paint.setStrokeJoin(Join.ROUND);
- paint.setStrokeWidth(mOutlineWidth);
-
- for (int i = 0; i < lineCount; i++) {
- layout.drawText(c, i, i);
- }
- }
-
- if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
- paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
- }
-
- paint.setColor(mForegroundColor);
- paint.setStyle(Style.FILL);
-
- for (int i = 0; i < lineCount; i++) {
- layout.drawText(c, i, i);
- }
-
- c.restoreToCount(saveCount);
- }
-}
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.widget.TextView;
+import com.android.internal.widget.SubtitleView;
import com.android.settings.R;
/**
@Override
protected void onBindListItem(View view, int index) {
final float fontSize = CaptioningManager.getFontSize(getContext().getContentResolver());
- final CaptioningTextView preview = (CaptioningTextView) view.findViewById(R.id.preview);
+ final SubtitleView preview = (SubtitleView) view.findViewById(R.id.preview);
preview.setForegroundColor(Color.WHITE);
preview.setBackgroundColor(Color.TRANSPARENT);
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.widget.TextView;
+import com.android.internal.widget.SubtitleView;
import com.android.settings.R;
public class PresetPreference extends ListDialogPreference {
@Override
protected void onBindListItem(View view, int index) {
- final CaptioningTextView previewText = (CaptioningTextView) view.findViewById(
- R.id.preview);
+ final SubtitleView previewText = (SubtitleView) view.findViewById(R.id.preview);
final int value = getValueAt(index);
ToggleCaptioningPreferenceFragment.applyCaptionProperties(previewText, value);
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
+import com.android.internal.widget.SubtitleView;
import com.android.settings.R;
import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
public class ToggleCaptioningPreferenceFragment extends Fragment {
private CaptionPropertiesFragment mPropsFragment;
- private CaptioningTextView mPreviewText;
+ private SubtitleView mPreviewText;
@Override
public View onCreateView(
.findFragmentById(R.id.properties_fragment));
mPropsFragment.setParent(this);
- mPreviewText = (CaptioningTextView) view.findViewById(R.id.preview_text);
+ mPreviewText = (SubtitleView) view.findViewById(R.id.preview_text);
installActionBarToggleSwitch();
refreshPreviewText();
}
public void refreshPreviewText() {
- final CaptioningTextView preview = mPreviewText;
+ final SubtitleView preview = mPreviewText;
if (preview != null) {
final Activity activity = getActivity();
final ContentResolver cr = activity.getContentResolver();
}
}
- public static void applyCaptionProperties(CaptioningTextView previewText, int styleId) {
+ public static void applyCaptionProperties(SubtitleView previewText, int styleId) {
previewText.setStyle(styleId);
final Context context = previewText.getContext();
import android.content.Intent;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
+import android.provider.Settings;
import com.android.settings.R;
@Override
public void onRadioButtonClicked(RadioButtonPreference emiter) {
- int mode = LocationSettingsBase.MODE_LOCATION_OFF;
+ int mode = Settings.Secure.LOCATION_MODE_OFF;
if (emiter == mHighAccuracy) {
- mode = LocationSettingsBase.MODE_HIGH_ACCURACY;
+ mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
} else if (emiter == mBatterySaving) {
- mode = LocationSettingsBase.MODE_BATTERY_SAVING;
+ mode = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
} else if (emiter == mSensorsOnly) {
- mode = LocationSettingsBase.MODE_SENSORS_ONLY;
+ mode = Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
}
setLocationMode(mode);
}
@Override
public void onModeChanged(int mode) {
switch (mode) {
- case MODE_LOCATION_OFF:
+ case Settings.Secure.LOCATION_MODE_OFF:
Intent intent = new Intent();
PreferenceActivity pa = (PreferenceActivity) getActivity();
pa.finishPreferencePanel(LocationMode.this, Activity.RESULT_OK, intent);
break;
- case MODE_SENSORS_ONLY:
+ case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
updateRadioButtons(mSensorsOnly);
break;
- case MODE_BATTERY_SAVING:
+ case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
updateRadioButtons(mBatterySaving);
break;
- case MODE_HIGH_ACCURACY:
+ case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
updateRadioButtons(mHighAccuracy);
break;
default:
break;
}
- boolean enabled = (mode != MODE_LOCATION_OFF);
+ boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF);
mHighAccuracy.setEnabled(enabled);
mBatterySaving.setEnabled(enabled);
mSensorsOnly.setEnabled(enabled);
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.provider.Settings;
import android.view.Gravity;
import android.widget.CompoundButton;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryStatsHelper;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
/**
* Location access settings.
*/
mStatsHelper.destroy();
}
+ private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) {
+ // If there's some items to display, sort the items and add them to the container.
+ Collections.sort(prefs, new Comparator<Preference>() {
+ @Override
+ public int compare(Preference lhs, Preference rhs) {
+ return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
+ }
+ });
+ for (Preference entry : prefs) {
+ container.addPreference(entry);
+ }
+ }
+
private PreferenceScreen createPreferenceHierarchy() {
+ final PreferenceActivity activity = (PreferenceActivity) getActivity();
PreferenceScreen root = getPreferenceScreen();
if (root != null) {
root.removeAll();
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- PreferenceActivity activity = (PreferenceActivity) getActivity();
activity.startPreferencePanel(
LocationMode.class.getName(), null,
R.string.location_mode_screen_title, null, LocationSettings.this,
return true;
}
});
+
+ final PreferenceManager preferenceManager = getPreferenceManager();
+
mRecentLocationRequests =
(PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
- mLocationServices = (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
-
- PreferenceActivity activity = (PreferenceActivity) getActivity();
RecentLocationApps recentApps = new RecentLocationApps(activity, mStatsHelper);
- recentApps.fillAppList(mRecentLocationRequests);
+ List<Preference> recentLocationRequests = recentApps.getAppList(preferenceManager);
+ if (recentLocationRequests.size() > 0) {
+ addPreferencesSorted(recentLocationRequests, mRecentLocationRequests);
+ } else {
+ // If there's no item to display, add a "No recent apps" item.
+ PreferenceScreen screen = preferenceManager.createPreferenceScreen(activity);
+ screen.setTitle(R.string.location_no_recent_apps);
+ screen.setSelectable(false);
+ screen.setEnabled(false);
+ mRecentLocationRequests.addPreference(screen);
+ }
- SettingsInjector.addInjectedSettings(mLocationServices, activity, getPreferenceManager());
+ mLocationServices = (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
+ List<Preference> locationServices = SettingsInjector.getInjectedSettings(
+ activity, preferenceManager);
+ addPreferencesSorted(locationServices, mLocationServices);
// Only show the master switch when we're not in multi-pane mode, and not being used as
// Setup Wizard.
@Override
public void onModeChanged(int mode) {
switch (mode) {
- case MODE_LOCATION_OFF:
+ case Settings.Secure.LOCATION_MODE_OFF:
mLocationMode.setSummary(R.string.location_mode_location_off_title);
break;
- case MODE_SENSORS_ONLY:
+ case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
mLocationMode.setSummary(R.string.location_mode_sensors_only_title);
break;
- case MODE_BATTERY_SAVING:
+ case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
mLocationMode.setSummary(R.string.location_mode_battery_saving_title);
break;
- case MODE_HIGH_ACCURACY:
+ case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
mLocationMode.setSummary(R.string.location_mode_high_accuracy_title);
break;
default:
break;
}
- boolean enabled = (mode != MODE_LOCATION_OFF);
+ boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF);
mLocationMode.setEnabled(enabled);
- mRecentLocationRequests.setEnabled(enabled);
mLocationServices.setEnabled(enabled);
if (enabled != mSwitch.isChecked()) {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
- setLocationMode(MODE_HIGH_ACCURACY);
+ setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
} else {
- setLocationMode(MODE_LOCATION_OFF);
+ setLocationMode(Settings.Secure.LOCATION_MODE_OFF);
}
}
}
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
-import android.location.LocationManager;
import android.os.UserManager;
import android.provider.Settings;
-import android.util.Log;
import com.android.settings.SettingsPreferenceFragment;
* settings.
*/
public abstract class LocationSettingsBase extends SettingsPreferenceFragment {
- private static final String TAG = LocationSettingsBase.class.getSimpleName();
-
- /** Location disabled */
- public static final int MODE_LOCATION_OFF = 0;
- /** GPS-only */
- public static final int MODE_SENSORS_ONLY = 1;
- /** Network location only */
- public static final int MODE_BATTERY_SAVING = 2;
- /** GPS and network location */
- public static final int MODE_HIGH_ACCURACY = 3;
-
private ContentQueryMap mContentQueryMap;
private Observer mSettingsObserver;
public abstract void onModeChanged(int mode);
public void setLocationMode(int mode) {
- boolean gps = false;
- boolean network = false;
- switch (mode) {
- case MODE_LOCATION_OFF:
- break;
- case MODE_SENSORS_ONLY:
- gps = true;
- break;
- case MODE_BATTERY_SAVING:
- network = true;
- break;
- case MODE_HIGH_ACCURACY:
- gps = true;
- network = true;
- break;
- default:
- Log.wtf(TAG, "Invalid location mode: " + mode);
- }
final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
return;
}
- // TODO(lifu): use new atomic API to change location mode.
- Settings.Secure.setLocationProviderEnabled(
- getContentResolver(), LocationManager.GPS_PROVIDER, gps);
- Settings.Secure.setLocationProviderEnabled(
- getContentResolver(), LocationManager.NETWORK_PROVIDER, network);
+ Settings.Secure.setLocationMode(getContentResolver(), mode);
refreshLocationMode();
}
public void refreshLocationMode() {
ContentResolver res = getContentResolver();
- boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled(
- res, LocationManager.GPS_PROVIDER);
- boolean networkEnabled = Settings.Secure.isLocationProviderEnabled(
- res, LocationManager.NETWORK_PROVIDER);
- boolean enabled = gpsEnabled || networkEnabled;
- if (!enabled) {
- onModeChanged(MODE_LOCATION_OFF);
- } else if (gpsEnabled && !networkEnabled) {
- onModeChanged(MODE_SENSORS_ONLY);
- } else if (!gpsEnabled && networkEnabled) {
- onModeChanged(MODE_BATTERY_SAVING);
- } else {
- onModeChanged(MODE_HIGH_ACCURACY);
- }
+ int mode = Settings.Secure.getLocationMode(getContentResolver());
+ onModeChanged(mode);
}
}
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.Log;
import com.android.settings.fuelgauge.BatteryStatsHelper;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
* Fills a list of applications which queried location recently within
* specified time.
*/
- public void fillAppList(PreferenceCategory container) {
+ public List<Preference> getAppList(PreferenceManager preferenceManager) {
// Retrieve Uid-based battery blaming info and generate a package to BatterySipper HashMap
// for later faster looking up.
mStatsHelper.refreshStats();
AppOpsManager.OP_MONITOR_LOCATION,
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
});
- PreferenceManager preferenceManager = container.getPreferenceManager();
// Process the AppOps list and generate a preference list.
- ArrayList<PreferenceScreen> prefs = new ArrayList<PreferenceScreen>();
+ ArrayList<Preference> prefs = new ArrayList<Preference>();
long now = System.currentTimeMillis();
for (AppOpsManager.PackageOps ops : appOps) {
BatterySipperWrapper wrapper = sipperMap.get(ops.getUid());
}
}
- if (prefs.size() > 0) {
- // If there's some items to display, sort the items and add them to the container.
- Collections.sort(prefs, new Comparator<PreferenceScreen>() {
- @Override
- public int compare(PreferenceScreen lhs, PreferenceScreen rhs) {
- return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
- }
- });
- for (PreferenceScreen entry : prefs) {
- container.addPreference(entry);
- }
- } else {
- // If there's no item to display, add a "No recent apps" item.
- PreferenceScreen screen = preferenceManager.createPreferenceScreen(mActivity);
- screen.setTitle(R.string.location_no_recent_apps);
- screen.setSelectable(false);
- screen.setEnabled(false);
- container.addPreference(screen);
- }
+ return prefs;
}
/**
package com.android.settings.location;
-import android.R;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Message;
import android.os.Messenger;
import android.preference.Preference;
-import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.text.TextUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import com.android.settings.R;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
* Code-sharing would require extracting {@link
* android.content.pm.RegisteredServicesCache#parseServiceAttributes(android.content.res.Resources,
* String, android.util.AttributeSet)} into an interface, which didn't seem worth it.
+ *
+ * TODO: register a broadcast receiver that calls updateUI() when it receives
+ * {@link SettingInjectorService#UPDATE_INTENT}.
*/
class SettingsInjector {
-
private static final String TAG = "SettingsInjector";
+ private static final long INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS = 1000;
+
/**
* Intent action marking the receiver as injecting a setting
*/
public static final String ATTRIBUTES_NAME = "injected-location-setting";
/**
- * Intent action a client should broadcast when the value of one of its injected settings has
- * changed, so that the setting can be updated in the UI.
- *
- * TODO: register a broadcast receiver that calls updateUI() when it receives this intent
- */
- public static final String UPDATE_INTENT =
- "com.android.settings.InjectedLocationSettingChanged";
-
- /**
* Returns a list with one {@link InjectedSetting} object for each {@link android.app.Service}
* that responds to {@link #RECEIVER_INTENT} and provides the expected setting metadata.
*
* Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
*
- * TODO: sort alphabetically
- *
* TODO: unit test
*/
public static List<InjectedSetting> getSettings(Context context) {
private static InjectedSetting parseAttributes(
String packageName, String className, Resources res, AttributeSet attrs) {
- TypedArray sa = res.obtainAttributes(attrs, R.styleable.InjectedLocationSetting);
+ TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.InjectedLocationSetting);
try {
// Note that to help guard against malicious string injection, we do not allow dynamic
// specification of the label (setting title)
- final int labelId = sa.getResourceId(R.styleable.InjectedLocationSetting_label, 0);
- final String label = sa.getString(R.styleable.InjectedLocationSetting_label);
- final int iconId = sa.getResourceId(R.styleable.InjectedLocationSetting_icon, 0);
+ final int labelId = sa.getResourceId(
+ android.R.styleable.InjectedLocationSetting_label, 0);
+ final String label = sa.getString(android.R.styleable.InjectedLocationSetting_label);
+ final int iconId = sa.getResourceId(
+ android.R.styleable.InjectedLocationSetting_icon, 0);
final String settingsActivity =
- sa.getString(R.styleable.InjectedLocationSetting_settingsActivity);
+ sa.getString(android.R.styleable.InjectedLocationSetting_settingsActivity);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "parsed labelId: " + labelId + ", label: " + label
+ ", iconId: " + iconId);
}
}
+ private static final class StatusLoader {
+ private final Context mContext;
+ private final Intent mIntent;
+ private final StatusLoader mPrev;
+
+ private boolean mLoaded = false;
+
+ /**
+ * Creates a loader and chains with the previous loader.
+ */
+ public StatusLoader(Context context, Intent intent, StatusLoader prev) {
+ mContext = context;
+ mIntent = intent;
+ mPrev = prev;
+ }
+
+ /**
+ * If the current message hasn't been loaded, loads the status messages
+ * and set time out for the next message.
+ */
+ public void loadIfNotLoaded() {
+ if (mLoaded) {
+ return;
+ }
+
+ mContext.startService(mIntent);
+ if (mPrev != null) {
+ Handler handler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // Continue with the next item in the chain.
+ mPrev.loadIfNotLoaded();
+ }
+ };
+ // Ensure that we start loading the previous setting in the chain if the current
+ // setting hasn't loaded before the timeout
+ handler.sendMessageDelayed(
+ Message.obtain(handler), INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS);
+ }
+ mLoaded = true;
+ }
+ }
+
/**
- * Add settings that other apps have injected.
+ * Gets a list of preferences that other apps have injected.
*
* TODO: extract InjectedLocationSettingGetter that returns an iterable over
* InjectedSetting objects, so that this class can focus on UI
*/
- public static void addInjectedSettings(PreferenceGroup group, Context context,
+ public static List<Preference> getInjectedSettings(Context context,
PreferenceManager preferenceManager) {
Iterable<InjectedSetting> settings = getSettings(context);
+ ArrayList<Preference> prefs = new ArrayList<Preference>();
+ StatusLoader loader = null;
for (InjectedSetting setting : settings) {
- Preference pref = addServiceSetting(context, group, setting, preferenceManager);
+ Preference pref = addServiceSetting(context, prefs, setting, preferenceManager);
+ Intent intent = createUpdatingIntent(context, pref, setting, loader);
+ loader = new StatusLoader(context, intent, loader);
+ }
- // TODO: to prevent churn from multiple live broadcast receivers, don't trigger
- // the next update until the sooner of: the current update completes or 1-2 seconds
- // after the current update was started.
- updateSetting(context, pref, setting);
+ // Start a thread to load each list item status.
+ if (loader != null) {
+ loader.loadIfNotLoaded();
}
+
+ return prefs;
}
/**
* Adds an injected setting to the root with status "Loading...".
*/
private static PreferenceScreen addServiceSetting(Context context,
- PreferenceGroup group, InjectedSetting info, PreferenceManager preferenceManager) {
+ List<Preference> prefs, InjectedSetting info, PreferenceManager preferenceManager) {
PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
screen.setTitle(info.title);
- screen.setSummary("Loading...");
+ screen.setSummary(R.string.location_loading_injected_setting);
PackageManager pm = context.getPackageManager();
Drawable icon = pm.getDrawable(info.packageName, info.iconId, null);
screen.setIcon(icon);
settingIntent.setClassName(info.packageName, info.settingsActivity);
screen.setIntent(settingIntent);
- group.addPreference(screen);
+ prefs.add(screen);
return screen;
}
/**
- * Ask the receiver for the current status for the setting, and display it when it replies.
+ * Creates an Intent to ask the receiver for the current status for the setting, and display it
+ * when it replies.
*/
- private static void updateSetting(Context context,
- final Preference pref, final InjectedSetting info) {
+ private static Intent createUpdatingIntent(Context context,
+ final Preference pref, final InjectedSetting info, final StatusLoader prev) {
+ final Intent receiverIntent = info.getServiceIntent();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
pref.setSummary(status);
pref.setEnabled(enabled);
+ if (prev != null) {
+ prev.loadIfNotLoaded();
+ }
}
};
Messenger messenger = new Messenger(handler);
- Intent receiverIntent = info.getServiceIntent();
receiverIntent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, info + ": sending rcv-intent: " + receiverIntent + ", handler: " + handler);
}
- context.startService(receiverIntent);
+ return receiverIntent;
}
}
@Override
public int getActualState(Context context) {
ContentResolver resolver = context.getContentResolver();
- return Settings.Secure.isLocationMasterSwitchEnabled(resolver)
- ? STATE_ENABLED : STATE_DISABLED;
+ int currentLocationMode = Settings.Secure.getLocationMode(resolver);
+ switch (currentLocationMode) {
+ case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
+ case Settings.Secure.LOCATION_MODE_OFF:
+ return STATE_DISABLED;
+ }
+
+ return STATE_ENABLED;
}
@Override
final UserManager um =
(UserManager) context.getSystemService(Context.USER_SERVICE);
if (!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
- Settings.Secure.setLocationMasterSwitchEnabled(resolver, desiredState);
+ int mode = desiredState
+ ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+ : Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
+ Settings.Secure.setLocationMode(resolver, mode);
return desiredState;
}
- return Settings.Secure.isLocationMasterSwitchEnabled(resolver);
+ return getActualState(context) == STATE_ENABLED;
}
@Override