Reduce jank in wifi settings

- Fix view recycling for AccessPointPreferences by adding a dummy
   during initial inflation
 - Cut down on what is done during onBindView and refresh()
 - Try to re-use AccessPointPreferences when possible

Some jank still occurs when scan results come in, but it is less
than before.

Bug: 16518752
Change-Id: I2619303281dd50aa3864783c49738ae9f221834a
This commit is contained in:
Jason Monk
2015-06-29 13:28:21 -04:00
parent 52dce9d334
commit 55dd8869db
4 changed files with 79 additions and 47 deletions

View File

@@ -19,4 +19,9 @@
android:title="@string/wifi_settings" android:title="@string/wifi_settings"
settings:keywords="@string/keywords_wifi"> settings:keywords="@string/keywords_wifi">
<!-- Needed so PreferenceGroupAdapter allows AccessPointPreference to be
recycled. Removed in onResume -->
<com.android.settings.wifi.AccessPointPreference
android:key="dummy" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -16,12 +16,15 @@
package com.android.settings.wifi; package com.android.settings.wifi;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.StateListDrawable;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.os.Looper; import android.os.Looper;
import android.os.UserHandle; import android.os.UserHandle;
import android.preference.Preference; import android.preference.Preference;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@@ -37,22 +40,39 @@ public class AccessPointPreference extends Preference {
private static int[] wifi_signal_attributes = { R.attr.wifi_signal }; private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
private final StateListDrawable mWifiSld;
private final int mBadgePadding;
private final UserBadgeCache mBadgeCache;
private TextView mTitleView; private TextView mTitleView;
private TextView mSummaryView;
private boolean mShowSummary = true;
private boolean mForSavedNetworks = false; private boolean mForSavedNetworks = false;
private AccessPoint mAccessPoint; private AccessPoint mAccessPoint;
private Drawable mBadge; private Drawable mBadge;
private int mBadgePadding;
private int mLevel; private int mLevel;
public AccessPointPreference(AccessPoint accessPoint, Context context, // Used for dummy pref.
public AccessPointPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mWifiSld = null;
mBadgePadding = 0;
mBadgeCache = null;
}
public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
boolean forSavedNetworks) { boolean forSavedNetworks) {
super(context); super(context);
mBadgeCache = cache;
mAccessPoint = accessPoint; mAccessPoint = accessPoint;
mForSavedNetworks = forSavedNetworks; mForSavedNetworks = forSavedNetworks;
mAccessPoint.setTag(this); mAccessPoint.setTag(this);
mLevel = -1; mLevel = -1;
mWifiSld = (StateListDrawable) context.getTheme()
.obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
// Distance from the end of the title at which this AP's user badge should sit.
mBadgePadding = context.getResources()
.getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
refresh(); refresh();
} }
@@ -63,6 +83,10 @@ public class AccessPointPreference extends Preference {
@Override @Override
protected void onBindView(View view) { protected void onBindView(View view) {
super.onBindView(view); super.onBindView(view);
if (mAccessPoint == null) {
// Used for dummy pref.
return;
}
Drawable drawable = getIcon(); Drawable drawable = getIcon();
if (drawable != null) { if (drawable != null) {
drawable.setLevel(mLevel); drawable.setLevel(mLevel);
@@ -74,11 +98,6 @@ public class AccessPointPreference extends Preference {
mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mBadge, null); mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mBadge, null);
mTitleView.setCompoundDrawablePadding(mBadgePadding); mTitleView.setCompoundDrawablePadding(mBadgePadding);
} }
mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
mSummaryView.setVisibility(mShowSummary ? View.VISIBLE : View.GONE);
updateBadge(getContext());
} }
protected void updateIcon(int level, Context context) { protected void updateIcon(int level, Context context) {
@@ -88,15 +107,13 @@ public class AccessPointPreference extends Preference {
if (getIcon() == null) { if (getIcon() == null) {
// To avoid a drawing race condition, we first set the state (SECURE/NONE) and then // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
// set the icon (drawable) to that state's drawable. // set the icon (drawable) to that state's drawable.
StateListDrawable sld = (StateListDrawable) context.getTheme()
.obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
// If sld is null then we are indexing and therefore do not have access to // If sld is null then we are indexing and therefore do not have access to
// (nor need to display) the drawable. // (nor need to display) the drawable.
if (sld != null) { if (mWifiSld != null) {
sld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) mWifiSld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
? STATE_SECURED ? STATE_SECURED
: STATE_NONE); : STATE_NONE);
Drawable drawable = sld.getCurrent(); Drawable drawable = mWifiSld.getCurrent();
if (!mForSavedNetworks) { if (!mForSavedNetworks) {
setIcon(drawable); setIcon(drawable);
} else { } else {
@@ -111,12 +128,9 @@ public class AccessPointPreference extends Preference {
WifiConfiguration config = mAccessPoint.getConfig(); WifiConfiguration config = mAccessPoint.getConfig();
if (config != null) { if (config != null) {
// Fetch badge (may be null) // Fetch badge (may be null)
UserHandle creatorUser = new UserHandle(UserHandle.getUserId(config.creatorUid)); // Get the badge using a cache since the PM will ask the UserManager for the list
mBadge = context.getPackageManager().getUserBadgeForDensity(creatorUser, 0 /* dpi */); // of profiles every time otherwise.
mBadge = mBadgeCache.getUserBadge(config.creatorUid);
// Distance from the end of the title at which this AP's user badge should sit.
mBadgePadding = context.getResources()
.getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
} }
} }
@@ -139,20 +153,8 @@ public class AccessPointPreference extends Preference {
} }
updateBadge(context); updateBadge(context);
// Force new summary setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
setSummary(null); : mAccessPoint.getSettingsSummary());
String summary = mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
: mAccessPoint.getSettingsSummary();
boolean showSummary = summary.length() > 0;
if (showSummary) {
setSummary(summary);
}
if (showSummary != mShowSummary) {
mShowSummary = showSummary;
notifyChanged();
}
} }
@Override @Override
@@ -181,4 +183,23 @@ public class AccessPointPreference extends Preference {
notifyChanged(); notifyChanged();
} }
}; };
public static class UserBadgeCache {
private final SparseArray<Drawable> mBadges = new SparseArray<>();
private final PackageManager mPm;
UserBadgeCache(PackageManager pm) {
mPm = pm;
}
private Drawable getUserBadge(int userId) {
int index = mBadges.indexOfKey(userId);
if (index < 0) {
Drawable badge = mPm.getUserBadgeForDensity(new UserHandle(userId), 0 /* dpi */);
mBadges.put(userId, badge);
return badge;
}
return mBadges.valueAt(index);
}
}
} }

View File

@@ -16,19 +16,12 @@
package com.android.settings.wifi; package com.android.settings.wifi;
import android.app.AppGlobals;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.util.Log; import android.util.Log;
@@ -39,12 +32,13 @@ import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw; import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.wifi.AccessPointPreference.UserBadgeCache;
import com.android.settingslib.wifi.AccessPoint; import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.WifiTracker; import com.android.settingslib.wifi.WifiTracker;
import java.util.Collections;
import java.util.Comparator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
@@ -60,6 +54,8 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment
private Bundle mAccessPointSavedState; private Bundle mAccessPointSavedState;
private AccessPoint mSelectedAccessPoint; private AccessPoint mSelectedAccessPoint;
private UserBadgeCache mUserBadgeCache;
// Instance state key // Instance state key
private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
@@ -72,6 +68,7 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wifi_display_saved_access_points); addPreferencesFromResource(R.xml.wifi_display_saved_access_points);
mUserBadgeCache = new UserBadgeCache(getPackageManager());
} }
@Override @Override
@@ -113,7 +110,7 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment
final int accessPointsSize = accessPoints.size(); final int accessPointsSize = accessPoints.size();
for (int i = 0; i < accessPointsSize; ++i){ for (int i = 0; i < accessPointsSize; ++i){
AccessPointPreference preference = new AccessPointPreference(accessPoints.get(i), AccessPointPreference preference = new AccessPointPreference(accessPoints.get(i),
context, true); context, mUserBadgeCache, true);
preference.setIcon(null); preference.setIcon(null);
preferenceScreen.addPreference(preference); preferenceScreen.addPreference(preference);
} }

View File

@@ -78,6 +78,7 @@ import com.android.settings.location.ScanningSettings;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw; import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.wifi.AccessPointPreference.UserBadgeCache;
import com.android.settingslib.wifi.AccessPoint; import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.AccessPoint.AccessPointListener; import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
import com.android.settingslib.wifi.WifiTracker; import com.android.settingslib.wifi.WifiTracker;
@@ -159,6 +160,8 @@ public class WifiSettings extends RestrictedSettingsFragment
private HandlerThread mBgThread; private HandlerThread mBgThread;
private UserBadgeCache mUserBadgeCache;
/* End of "used in Wifi Setup context" */ /* End of "used in Wifi Setup context" */
public WifiSettings() { public WifiSettings() {
@@ -177,6 +180,9 @@ public class WifiSettings extends RestrictedSettingsFragment
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
addPreferencesFromResource(R.xml.wifi_settings);
mUserBadgeCache = new UserBadgeCache(getPackageManager());
mBgThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); mBgThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start(); mBgThread.start();
} }
@@ -270,8 +276,6 @@ public class WifiSettings extends RestrictedSettingsFragment
} }
} }
addPreferencesFromResource(R.xml.wifi_settings);
mEmptyView = initEmptyView(); mEmptyView = initEmptyView();
registerForContextMenu(getListView()); registerForContextMenu(getListView());
setHasOptionsMenu(true); setHasOptionsMenu(true);
@@ -311,6 +315,7 @@ public class WifiSettings extends RestrictedSettingsFragment
public void onResume() { public void onResume() {
final Activity activity = getActivity(); final Activity activity = getActivity();
super.onResume(); super.onResume();
removePreference("dummy");
if (mWifiEnabler != null) { if (mWifiEnabler != null) {
mWifiEnabler.resume(activity); mWifiEnabler.resume(activity);
} }
@@ -652,8 +657,12 @@ public class WifiSettings extends RestrictedSettingsFragment
// Ignore access points that are out of range. // Ignore access points that are out of range.
if (accessPoint.getLevel() != -1) { if (accessPoint.getLevel() != -1) {
hasAvailableAccessPoints = true; hasAvailableAccessPoints = true;
if (accessPoint.getTag() != null) {
getPreferenceScreen().addPreference((Preference) accessPoint.getTag());
continue;
}
AccessPointPreference preference = new AccessPointPreference(accessPoint, AccessPointPreference preference = new AccessPointPreference(accessPoint,
getActivity(), false); getActivity(), mUserBadgeCache, false);
if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr()) if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
&& !accessPoint.isSaved() && !accessPoint.isSaved()