Snap for 5090430 from e2ed46e906 to qt-release
Change-Id: I2c06ccf38c5971656731ea91bcde4602e33aa5f1
This commit is contained in:
@@ -20,7 +20,9 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -30,9 +32,11 @@ import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TabHost;
|
||||
@@ -40,6 +44,7 @@ import android.widget.TabHost.OnTabChangeListener;
|
||||
import android.widget.TabHost.TabContentFactory;
|
||||
import android.widget.TabHost.TabSpec;
|
||||
import android.widget.TabWidget;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
@@ -118,6 +123,9 @@ public class IccLockSettings extends SettingsPreferenceFragment
|
||||
private static final int MSG_CHANGE_ICC_PIN_COMPLETE = 101;
|
||||
private static final int MSG_SIM_STATE_CHANGED = 102;
|
||||
|
||||
// @see android.widget.Toast$TN
|
||||
private static final long LONG_DURATION_TIMEOUT = 7000;
|
||||
|
||||
// For replies from IccCard interface
|
||||
private Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
@@ -461,8 +469,7 @@ public class IccLockSettings extends SettingsPreferenceFragment
|
||||
if (exception instanceof CommandException) {
|
||||
CommandException.Error err = ((CommandException)(exception)).getCommandError();
|
||||
if (err == CommandException.Error.PASSWORD_INCORRECT) {
|
||||
Toast.makeText(getContext(), getPinPasswordErrorMessage(attemptsRemaining),
|
||||
Toast.LENGTH_LONG).show();
|
||||
createCustomTextToast(getPinPasswordErrorMessage(attemptsRemaining));
|
||||
} else {
|
||||
if (mToState) {
|
||||
Toast.makeText(getContext(), mRes.getString
|
||||
@@ -478,11 +485,56 @@ public class IccLockSettings extends SettingsPreferenceFragment
|
||||
resetDialogState();
|
||||
}
|
||||
|
||||
private void createCustomTextToast(CharSequence errorMessage) {
|
||||
// Cannot overlay Toast on PUK unlock screen.
|
||||
// The window type of Toast is set by NotificationManagerService.
|
||||
// It can't be overwritten by LayoutParams.type.
|
||||
// Ovarlay a custom window with LayoutParams (TYPE_STATUS_BAR_PANEL) on PUK unlock screen.
|
||||
View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE))
|
||||
.inflate(com.android.internal.R.layout.transient_notification, null);
|
||||
TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message);
|
||||
tv.setText(errorMessage);
|
||||
|
||||
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
|
||||
final Configuration config = v.getContext().getResources().getConfiguration();
|
||||
final int gravity = Gravity.getAbsoluteGravity(
|
||||
getContext().getResources().getInteger(
|
||||
com.android.internal.R.integer.config_toastDefaultGravity),
|
||||
config.getLayoutDirection());
|
||||
params.gravity = gravity;
|
||||
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
|
||||
params.horizontalWeight = 1.0f;
|
||||
}
|
||||
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
|
||||
params.verticalWeight = 1.0f;
|
||||
}
|
||||
params.y = getContext().getResources().getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.toast_y_offset);
|
||||
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.format = PixelFormat.TRANSLUCENT;
|
||||
params.windowAnimations = com.android.internal.R.style.Animation_Toast;
|
||||
params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
|
||||
params.setTitle(errorMessage);
|
||||
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
|
||||
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
wm.addView(v, params);
|
||||
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
wm.removeViewImmediate(v);
|
||||
}
|
||||
}, LONG_DURATION_TIMEOUT);
|
||||
}
|
||||
|
||||
private void iccPinChanged(boolean success, int attemptsRemaining) {
|
||||
if (!success) {
|
||||
Toast.makeText(getContext(), getPinPasswordErrorMessage(attemptsRemaining),
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
createCustomTextToast(getPinPasswordErrorMessage(attemptsRemaining));
|
||||
} else {
|
||||
Toast.makeText(getContext(), mRes.getString(R.string.sim_change_succeeded),
|
||||
Toast.LENGTH_SHORT)
|
||||
|
||||
@@ -148,49 +148,7 @@ public class BatteryInfo {
|
||||
new AsyncTask<Void, Void, BatteryInfo>() {
|
||||
@Override
|
||||
protected BatteryInfo doInBackground(Void... params) {
|
||||
final BatteryStats stats;
|
||||
final long batteryStatsTime = System.currentTimeMillis();
|
||||
if (statsHelper == null) {
|
||||
final BatteryStatsHelper localStatsHelper = new BatteryStatsHelper(context,
|
||||
true);
|
||||
localStatsHelper.create((Bundle) null);
|
||||
stats = localStatsHelper.getStats();
|
||||
} else {
|
||||
stats = statsHelper.getStats();
|
||||
}
|
||||
BatteryUtils.logRuntime(LOG_TAG, "time for getStats", batteryStatsTime);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
PowerUsageFeatureProvider provider =
|
||||
FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
|
||||
final long elapsedRealtimeUs =
|
||||
PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
|
||||
|
||||
Intent batteryBroadcast = context.registerReceiver(null,
|
||||
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
// 0 means we are discharging, anything else means charging
|
||||
boolean discharging =
|
||||
batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
|
||||
|
||||
if (discharging && provider != null
|
||||
&& provider.isEnhancedBatteryPredictionEnabled(context)) {
|
||||
Estimate estimate = provider.getEnhancedBatteryPrediction(context);
|
||||
if (estimate != null) {
|
||||
BatteryUtils
|
||||
.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime);
|
||||
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
|
||||
estimate, elapsedRealtimeUs, shortString);
|
||||
}
|
||||
}
|
||||
long prediction = discharging
|
||||
? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0;
|
||||
Estimate estimate = new Estimate(
|
||||
PowerUtil.convertUsToMs(prediction),
|
||||
false, /* isBasedOnUsage */
|
||||
Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
|
||||
BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime);
|
||||
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
|
||||
estimate, elapsedRealtimeUs, shortString);
|
||||
return getBatteryInfo(context, statsHelper, shortString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,6 +160,53 @@ public class BatteryInfo {
|
||||
}.execute();
|
||||
}
|
||||
|
||||
public static BatteryInfo getBatteryInfo(final Context context,
|
||||
final BatteryStatsHelper statsHelper, boolean shortString) {
|
||||
final BatteryStats stats;
|
||||
final long batteryStatsTime = System.currentTimeMillis();
|
||||
if (statsHelper == null) {
|
||||
final BatteryStatsHelper localStatsHelper = new BatteryStatsHelper(context,
|
||||
true);
|
||||
localStatsHelper.create((Bundle) null);
|
||||
stats = localStatsHelper.getStats();
|
||||
} else {
|
||||
stats = statsHelper.getStats();
|
||||
}
|
||||
BatteryUtils.logRuntime(LOG_TAG, "time for getStats", batteryStatsTime);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
PowerUsageFeatureProvider provider =
|
||||
FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
|
||||
final long elapsedRealtimeUs =
|
||||
PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
|
||||
|
||||
final Intent batteryBroadcast = context.registerReceiver(null,
|
||||
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
// 0 means we are discharging, anything else means charging
|
||||
final boolean discharging =
|
||||
batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
|
||||
|
||||
if (discharging && provider != null
|
||||
&& provider.isEnhancedBatteryPredictionEnabled(context)) {
|
||||
Estimate estimate = provider.getEnhancedBatteryPrediction(context);
|
||||
if (estimate != null) {
|
||||
BatteryUtils
|
||||
.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime);
|
||||
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
|
||||
estimate, elapsedRealtimeUs, shortString);
|
||||
}
|
||||
}
|
||||
final long prediction = discharging
|
||||
? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0;
|
||||
final Estimate estimate = new Estimate(
|
||||
PowerUtil.convertUsToMs(prediction),
|
||||
false, /* isBasedOnUsage */
|
||||
Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
|
||||
BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime);
|
||||
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
|
||||
estimate, elapsedRealtimeUs, shortString);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast,
|
||||
BatteryStats stats, long elapsedRealtimeUs, boolean shortString) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.slice.Slice;
|
||||
|
||||
import com.android.settings.homepage.deviceinfo.BatterySlice;
|
||||
import com.android.settings.homepage.deviceinfo.DataUsageSlice;
|
||||
import com.android.settings.homepage.deviceinfo.DeviceInfoSlice;
|
||||
import com.android.settingslib.utils.AsyncLoaderCompat;
|
||||
@@ -101,17 +102,15 @@ public class CardContentLoader extends AsyncLoaderCompat<List<ContextualCard>> {
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setIsHalfWidth(false)
|
||||
.build());
|
||||
//TODO(b/115971399): Will change following values of SliceUri and Name
|
||||
// after landing these slice cards.
|
||||
// add(new ContextualCard.Builder()
|
||||
// .setSliceUri("content://com.android.settings.slices/battery_card")
|
||||
// .setName(packageName + "/" + "battery_card")
|
||||
// .setPackageName(packageName)
|
||||
// .setRankingScore(rankingScore)
|
||||
// .setAppVersion(appVersionCode)
|
||||
// .setCardType(ContextualCard.CardType.SLICE)
|
||||
// .setIsHalfWidth(true)
|
||||
// .build());
|
||||
add(new ContextualCard.Builder()
|
||||
.setSliceUri(BatterySlice.BATTERY_CARD_URI)
|
||||
.setName(BatterySlice.PATH_BATTERY_INFO)
|
||||
.setPackageName(packageName)
|
||||
.setRankingScore(rankingScore)
|
||||
.setAppVersion(appVersionCode)
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setIsHalfWidth(false)
|
||||
.build());
|
||||
add(new ContextualCard.Builder()
|
||||
.setSliceUri(DeviceInfoSlice.DEVICE_INFO_CARD_URI)
|
||||
.setName(DeviceInfoSlice.PATH_DEVICE_INFO)
|
||||
@@ -154,6 +153,7 @@ public class CardContentLoader extends AsyncLoaderCompat<List<ContextualCard>> {
|
||||
|
||||
final Slice slice = Slice.bindSlice(mContext, uri, SUPPORTED_SPECS);
|
||||
if (slice == null || slice.hasHint(HINT_ERROR)) {
|
||||
Log.w(TAG, "Failed to bind slice, not eligible for display " + uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,13 @@ public class SettingsHomepageActivity extends SettingsBaseActivity {
|
||||
private void showFragment(Fragment fragment, int id, String tag) {
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
fragmentTransaction.add(id, fragment, tag);
|
||||
final Fragment showFragment = fragmentManager.findFragmentById(id);
|
||||
|
||||
if (showFragment == null) {
|
||||
fragmentTransaction.add(id, fragment, tag);
|
||||
} else {
|
||||
fragmentTransaction.show(showFragment);
|
||||
}
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import static android.provider.SettingsSlicesContract.KEY_WIFI;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.settings.homepage.deviceinfo.BatterySlice;
|
||||
import com.android.settings.homepage.deviceinfo.DataUsageSlice;
|
||||
import com.android.settings.homepage.deviceinfo.DeviceInfoSlice;
|
||||
import com.android.settings.homepage.deviceinfo.StorageSlice;
|
||||
@@ -63,12 +64,18 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
|
||||
.setSliceUri(EmergencyInfoSlice.EMERGENCY_INFO_CARD_URI.toString())
|
||||
.setCardName(EmergencyInfoSlice.PATH_EMERGENCY_INFO_CARD)
|
||||
.build();
|
||||
final ContextualCard batteryInfoCard =
|
||||
ContextualCard.newBuilder()
|
||||
.setSliceUri(BatterySlice.BATTERY_CARD_URI.toSafeString())
|
||||
.setCardName(BatterySlice.PATH_BATTERY_INFO)
|
||||
.build();
|
||||
final ContextualCardList cards = ContextualCardList.newBuilder()
|
||||
.addCard(wifiCard)
|
||||
.addCard(dataUsageCard)
|
||||
.addCard(deviceInfoCard)
|
||||
.addCard(storageInfoCard)
|
||||
.addCard(emergencyInfoCard)
|
||||
.addCard(batteryInfoCard)
|
||||
.build();
|
||||
|
||||
return cards;
|
||||
|
||||
156
src/com/android/settings/homepage/deviceinfo/BatterySlice.java
Normal file
156
src/com/android/settings/homepage/deviceinfo/BatterySlice.java
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.homepage.deviceinfo;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.fuelgauge.BatteryInfo;
|
||||
import com.android.settings.fuelgauge.PowerUsageSummary;
|
||||
import com.android.settings.slices.CustomSliceable;
|
||||
import com.android.settings.slices.SettingsSliceProvider;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
|
||||
/**
|
||||
* Utility class to build a Battery Slice, and handle all associated actions.
|
||||
*/
|
||||
public class BatterySlice implements CustomSliceable {
|
||||
private static final String TAG = "BatterySlice";
|
||||
|
||||
/**
|
||||
* The path denotes the unique name of battery slice.
|
||||
*/
|
||||
public static final String PATH_BATTERY_INFO = "battery_card";
|
||||
|
||||
/**
|
||||
* Backing Uri for the Battery Slice.
|
||||
*/
|
||||
public static final Uri BATTERY_CARD_URI = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(PATH_BATTERY_INFO)
|
||||
.build();
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private BatteryInfo mBatteryInfo;
|
||||
private boolean mIsBatteryInfoLoading;
|
||||
|
||||
public BatterySlice(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link BatterySlice} bound to {@link #BATTERY_CARD_URI}
|
||||
*/
|
||||
@Override
|
||||
public Slice getSlice() {
|
||||
if (mBatteryInfo == null) {
|
||||
mIsBatteryInfoLoading = true;
|
||||
loadBatteryInfo();
|
||||
}
|
||||
final IconCompat icon = IconCompat.createWithResource(mContext,
|
||||
R.drawable.ic_settings_battery);
|
||||
final CharSequence title = mContext.getText(R.string.power_usage_summary_title);
|
||||
final SliceAction primarySliceAction = new SliceAction(getPrimaryAction(), icon, title);
|
||||
final Slice slice = new ListBuilder(mContext, BATTERY_CARD_URI, ListBuilder.INFINITY)
|
||||
.setAccentColor(Utils.getColorAccentDefaultColor(mContext))
|
||||
.setHeader(new ListBuilder.HeaderBuilder().setTitle(title))
|
||||
.addRow(new ListBuilder.RowBuilder()
|
||||
.setTitle(getBatteryPercentString(), mIsBatteryInfoLoading)
|
||||
.setSubtitle(getSummary(), mIsBatteryInfoLoading)
|
||||
.setPrimaryAction(primarySliceAction))
|
||||
.build();
|
||||
mBatteryInfo = null;
|
||||
mIsBatteryInfoLoading = false;
|
||||
return slice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return BATTERY_CARD_URI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyChange(Intent intent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
final String screenTitle = mContext.getText(R.string.power_usage_summary_title).toString();
|
||||
final Uri contentUri = new Uri.Builder().appendPath(PATH_BATTERY_INFO).build();
|
||||
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
|
||||
PowerUsageSummary.class.getName(), PATH_BATTERY_INFO, screenTitle,
|
||||
MetricsProto.MetricsEvent.SLICE)
|
||||
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
|
||||
.setData(contentUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntentFilter getIntentFilter() {
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
|
||||
intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
|
||||
intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
|
||||
intentFilter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
|
||||
return intentFilter;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void loadBatteryInfo() {
|
||||
BatteryInfo.getBatteryInfo(mContext, info -> {
|
||||
mBatteryInfo = info;
|
||||
mContext.getContentResolver().notifyChange(getUri(), null);
|
||||
}, true);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
CharSequence getBatteryPercentString() {
|
||||
return mBatteryInfo == null ? null : mBatteryInfo.batteryPercentString;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
CharSequence getSummary() {
|
||||
if (mBatteryInfo == null) {
|
||||
return null;
|
||||
}
|
||||
return mBatteryInfo.remainingLabel == null ? mBatteryInfo.statusLabel
|
||||
: mBatteryInfo.remainingLabel;
|
||||
}
|
||||
|
||||
private PendingIntent getPrimaryAction() {
|
||||
final Intent intent = getIntent();
|
||||
return PendingIntent.getActivity(mContext, 0 /* requestCode */,
|
||||
intent, 0 /* flags */);
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,14 @@ import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.settings.homepage.deviceinfo.BatterySlice;
|
||||
import com.android.settings.homepage.deviceinfo.DataUsageSlice;
|
||||
import com.android.settings.homepage.deviceinfo.DeviceInfoSlice;
|
||||
import com.android.settings.homepage.deviceinfo.StorageSlice;
|
||||
import com.android.settings.wifi.WifiSlice;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Manages custom {@link androidx.slice.Slice Slices}, which are all Slices not backed by
|
||||
@@ -39,10 +41,12 @@ public class CustomSliceManager {
|
||||
protected final Map<Uri, Class<? extends CustomSliceable>> mUriMap;
|
||||
|
||||
private final Context mContext;
|
||||
private final Map<Uri, CustomSliceable> mSliceableCache;
|
||||
|
||||
public CustomSliceManager(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
mUriMap = new ArrayMap<>();
|
||||
mSliceableCache = new WeakHashMap<>();
|
||||
addSlices();
|
||||
}
|
||||
|
||||
@@ -53,13 +57,18 @@ public class CustomSliceManager {
|
||||
* the only thing that should be needed to create the object.
|
||||
*/
|
||||
public CustomSliceable getSliceableFromUri(Uri uri) {
|
||||
final Class clazz = mUriMap.get(uri);
|
||||
if (mSliceableCache.containsKey(uri)) {
|
||||
return mSliceableCache.get(uri);
|
||||
}
|
||||
|
||||
final Class clazz = mUriMap.get(uri);
|
||||
if (clazz == null) {
|
||||
throw new IllegalArgumentException("No Slice found for uri: " + uri);
|
||||
}
|
||||
|
||||
return CustomSliceable.createInstance(mContext, clazz);
|
||||
final CustomSliceable sliceable = CustomSliceable.createInstance(mContext, clazz);
|
||||
mSliceableCache.put(uri, sliceable);
|
||||
return sliceable;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,5 +102,6 @@ public class CustomSliceManager {
|
||||
mUriMap.put(DataUsageSlice.DATA_USAGE_CARD_URI, DataUsageSlice.class);
|
||||
mUriMap.put(DeviceInfoSlice.DEVICE_INFO_CARD_URI, DeviceInfoSlice.class);
|
||||
mUriMap.put(StorageSlice.STORAGE_CARD_URI, StorageSlice.class);
|
||||
mUriMap.put(BatterySlice.BATTERY_CARD_URI, BatterySlice.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.os.Looper;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
@@ -61,6 +62,7 @@ import java.util.List;
|
||||
*/
|
||||
public class WifiSlice implements CustomSliceable {
|
||||
|
||||
|
||||
/**
|
||||
* Backing Uri for the Wifi Slice.
|
||||
*/
|
||||
@@ -71,6 +73,9 @@ public class WifiSlice implements CustomSliceable {
|
||||
.appendPath(KEY_WIFI)
|
||||
.build();
|
||||
|
||||
@VisibleForTesting
|
||||
static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public WifiSlice(Context context) {
|
||||
@@ -115,26 +120,43 @@ public class WifiSlice implements CustomSliceable {
|
||||
.addEndItem(toggleSliceAction)
|
||||
.setPrimaryAction(primarySliceAction));
|
||||
|
||||
if (isWifiEnabled) {
|
||||
final List<AccessPoint> result = getBackgroundWorker().getResults();
|
||||
if (result != null && !result.isEmpty()) {
|
||||
for (AccessPoint ap : result) {
|
||||
listBuilder.addRow(getAccessPointRow(ap));
|
||||
}
|
||||
listBuilder.setSeeMoreAction(primaryAction);
|
||||
if (!isWifiEnabled) {
|
||||
return listBuilder.build();
|
||||
}
|
||||
|
||||
List<AccessPoint> result = getBackgroundWorker().getResults();
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
}
|
||||
final int apCount = result.size();
|
||||
// Add AP rows
|
||||
final CharSequence placeholder = mContext.getText(R.string.summary_placeholder);
|
||||
for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) {
|
||||
if (i < apCount) {
|
||||
listBuilder.addRow(getAccessPointRow(result.get(i)));
|
||||
} else {
|
||||
listBuilder.addRow(new RowBuilder()
|
||||
.setTitle(placeholder)
|
||||
.setSubtitle(placeholder));
|
||||
}
|
||||
}
|
||||
return listBuilder.build();
|
||||
// Add more button
|
||||
return listBuilder
|
||||
.setSeeMoreAction(primaryAction)
|
||||
.build();
|
||||
}
|
||||
|
||||
private RowBuilder getAccessPointRow(AccessPoint accessPoint) {
|
||||
final String title = accessPoint.getConfigName();
|
||||
final IconCompat levelIcon = IconCompat.createWithResource(mContext,
|
||||
com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
|
||||
final CharSequence apSummary = accessPoint.getSettingsSummary();
|
||||
final RowBuilder rowBuilder = new RowBuilder()
|
||||
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
|
||||
.setTitle(title)
|
||||
.setSubtitle(accessPoint.getSettingsSummary())
|
||||
.setSubtitle(!TextUtils.isEmpty(apSummary)
|
||||
? apSummary
|
||||
: mContext.getText(R.string.summary_placeholder))
|
||||
.setPrimaryAction(new SliceAction(
|
||||
getAccessPointAction(accessPoint), levelIcon, title));
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.android.settings.homepage.deviceinfo.BatterySlice;
|
||||
import com.android.settings.homepage.deviceinfo.DataUsageSlice;
|
||||
import com.android.settings.homepage.deviceinfo.DeviceInfoSlice;
|
||||
import com.android.settings.homepage.deviceinfo.StorageSlice;
|
||||
@@ -54,17 +55,18 @@ public class CardContentLoaderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createStaticCards_shouldReturnTwoCards() {
|
||||
public void createStaticCards_shouldReturnFourCards() {
|
||||
final List<ContextualCard> defaultData = mCardContentLoader.createStaticCards();
|
||||
|
||||
assertThat(defaultData).hasSize(2);
|
||||
assertThat(defaultData).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createStaticCards_shouldContainDataUsageAndDeviceInfo() {
|
||||
public void createStaticCards_shouldContainCorrectCards() {
|
||||
final Uri dataUsage = DataUsageSlice.DATA_USAGE_CARD_URI;
|
||||
final Uri deviceInfo = DeviceInfoSlice.DEVICE_INFO_CARD_URI;
|
||||
final List<Uri> expectedUris = Arrays.asList(dataUsage, deviceInfo);
|
||||
final Uri batteryInfo = BatterySlice.BATTERY_CARD_URI;
|
||||
final List<Uri> expectedUris = Arrays.asList(dataUsage, deviceInfo, batteryInfo);
|
||||
|
||||
final List<Uri> actualCardUris = mCardContentLoader.createStaticCards().stream().map(
|
||||
ContextualCard::getSliceUri).collect(Collectors.toList());
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.homepage.deviceinfo;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceItem;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.core.SliceAction;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.SliceTester;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class BatterySliceTest {
|
||||
|
||||
private Context mContext;
|
||||
private BatterySlice mBatterySlice;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
// Set-up specs for SliceMetadata.
|
||||
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
|
||||
|
||||
mBatterySlice = spy(new BatterySlice(mContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_shouldBeCorrectSliceContent() {
|
||||
doNothing().when(mBatterySlice).loadBatteryInfo();
|
||||
doReturn("10%").when(mBatterySlice).getBatteryPercentString();
|
||||
doReturn("test").when(mBatterySlice).getSummary();
|
||||
final Slice slice = mBatterySlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
|
||||
final SliceAction primaryAction = metadata.getPrimaryAction();
|
||||
final IconCompat expectedIcon = IconCompat.createWithResource(mContext,
|
||||
R.drawable.ic_settings_battery);
|
||||
assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedIcon.toString());
|
||||
|
||||
final List<SliceItem> sliceItems = slice.getItems();
|
||||
SliceTester.assertTitle(sliceItems, mContext.getString(R.string.power_usage_summary_title));
|
||||
}
|
||||
}
|
||||
@@ -213,7 +213,7 @@ public class SliceTester {
|
||||
for (SliceItem subTitleItem : titleItems) {
|
||||
if (TextUtils.equals(subTitleItem.getText(), title)) {
|
||||
hasTitle = true;
|
||||
assertThat(subTitleItem.getText()).isEqualTo(title);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
package com.android.settings.wifi;
|
||||
|
||||
import static android.app.slice.Slice.HINT_LIST_ITEM;
|
||||
import static android.app.slice.SliceItem.FORMAT_SLICE;
|
||||
|
||||
import static com.android.settings.wifi.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -29,6 +34,7 @@ import androidx.slice.SliceItem;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.core.SliceAction;
|
||||
import androidx.slice.core.SliceQuery;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -60,7 +66,7 @@ public class WifiSliceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWifiSlice_correctSliceContent() {
|
||||
public void getWifiSlice_shouldHaveTitleAndToggle() {
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
|
||||
|
||||
@@ -76,6 +82,17 @@ public class WifiSliceTest {
|
||||
SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWifiSlice_noAp_shouldReturnPlaceholder() {
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
|
||||
int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
|
||||
null /* nonHints */).size();
|
||||
// All AP rows + title row + see more row
|
||||
// (see more row will drop the last AP row, thus -1)
|
||||
assertThat(rows).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT - 1 + 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleUriChange_updatesWifi() {
|
||||
final Intent intent = mWifiSlice.getIntent();
|
||||
|
||||
Reference in New Issue
Block a user