Be more aggressive caching Vpn preference attrs

As any change to the preference title will cause it to lose focus,
best not to do this too often.

Change-Id: Ibac27ee1de42fd7ca05f3e3685b84f37dac39517
Fix: 28191965
This commit is contained in:
Robin Lee
2016-04-21 12:56:21 +01:00
parent e06d757a0c
commit b166ea2668
4 changed files with 71 additions and 87 deletions

View File

@@ -34,17 +34,43 @@ public class AppPreference extends ManageablePreference {
public static final int STATE_CONNECTED = LegacyVpnInfo.STATE_CONNECTED; public static final int STATE_CONNECTED = LegacyVpnInfo.STATE_CONNECTED;
public static final int STATE_DISCONNECTED = STATE_NONE; public static final int STATE_DISCONNECTED = STATE_NONE;
private String mPackageName; private final String mPackageName;
private String mName; private final String mName;
public AppPreference(Context context) { public AppPreference(Context context, int userId, String packageName) {
super(context, null /* attrs */); super(context, null /* attrs */);
}
@Override
public void setUserId(int userId) {
super.setUserId(userId); super.setUserId(userId);
update();
mPackageName = packageName;
// Fetch icon and VPN label
String label = packageName;
Drawable icon = null;
try {
// Make all calls to the package manager as the appropriate user.
Context userContext = getUserContext();
PackageManager pm = userContext.getPackageManager();
// The nested catch block is for the case that the app doesn't exist, so we can fall
// back to the default activity icon.
try {
PackageInfo pkgInfo = pm.getPackageInfo(mPackageName, 0 /* flags */);
if (pkgInfo != null) {
icon = pkgInfo.applicationInfo.loadIcon(pm);
label = VpnConfig.getVpnLabel(userContext, mPackageName).toString();
}
} catch (PackageManager.NameNotFoundException pkgNotFound) {
// Use default app label and icon as fallback
}
if (icon == null) {
icon = pm.getDefaultActivityIcon();
}
} catch (PackageManager.NameNotFoundException userNotFound) {
// No user, no useful information to obtain. Quietly fail.
}
mName = label;
setTitle(mName);
setIcon(icon);
} }
public PackageInfo getPackageInfo() { public PackageInfo getPackageInfo() {
@@ -64,48 +90,6 @@ public class AppPreference extends ManageablePreference {
return mPackageName; return mPackageName;
} }
public void setPackageName(String name) {
mPackageName = name;
update();
}
private void update() {
if (mPackageName == null || mUserId == UserHandle.USER_NULL) {
return;
}
mName = mPackageName;
Drawable icon = null;
try {
// Make all calls to the package manager as the appropriate user.
Context userContext = getUserContext();
PackageManager pm = userContext.getPackageManager();
// Fetch icon and VPN label- the nested catch block is for the case that the app doesn't
// exist, in which case we can fall back to the default activity icon for an activity in
// that user.
try {
PackageInfo pkgInfo = pm.getPackageInfo(mPackageName, 0 /* flags */);
if (pkgInfo != null) {
icon = pkgInfo.applicationInfo.loadIcon(pm);
mName = VpnConfig.getVpnLabel(userContext, mPackageName).toString();
}
} catch (PackageManager.NameNotFoundException pkgNotFound) {
// Use default app label and icon as fallback
}
if (icon == null) {
icon = pm.getDefaultActivityIcon();
}
} catch (PackageManager.NameNotFoundException userNotFound) {
// No user, no useful information to obtain. Quietly fail.
}
setTitle(mName);
setIcon(icon);
updateSummary();
notifyHierarchyChanged();
}
private Context getUserContext() throws PackageManager.NameNotFoundException { private Context getUserContext() throws PackageManager.NameNotFoundException {
UserHandle user = UserHandle.of(mUserId); UserHandle user = UserHandle.of(mUserId);
return getContext().createPackageContextAsUser( return getContext().createPackageContextAsUser(

View File

@@ -18,6 +18,7 @@ package com.android.settings.vpn2;
import android.content.Context; import android.content.Context;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import com.android.internal.net.VpnProfile; import com.android.internal.net.VpnProfile;
@@ -33,6 +34,7 @@ public class LegacyVpnPreference extends ManageablePreference {
LegacyVpnPreference(Context context) { LegacyVpnPreference(Context context) {
super(context, null /* attrs */); super(context, null /* attrs */);
setIcon(R.mipmap.ic_launcher_settings);
} }
public VpnProfile getProfile() { public VpnProfile getProfile() {
@@ -40,12 +42,13 @@ public class LegacyVpnPreference extends ManageablePreference {
} }
public void setProfile(VpnProfile profile) { public void setProfile(VpnProfile profile) {
mProfile = profile; final String oldLabel = (mProfile != null ? mProfile.name : null);
if (mProfile != null) { final String newLabel = (profile != null ? profile.name : null);
setIcon(R.mipmap.ic_launcher_settings); if (!TextUtils.equals(oldLabel, newLabel)) {
setTitle(mProfile.name); setTitle(newLabel);
notifyHierarchyChanged();
} }
notifyHierarchyChanged(); mProfile = profile;
} }
@Override @Override

View File

@@ -62,13 +62,18 @@ public abstract class ManageablePreference extends GearPreference {
} }
public void setState(int state) { public void setState(int state) {
mState = state; if (mState != state) {
updateSummary(); mState = state;
updateSummary();
notifyHierarchyChanged();
}
} }
public void setAlwaysOn(boolean isEnabled) { public void setAlwaysOn(boolean isEnabled) {
mIsAlwaysOn = isEnabled; if (mIsAlwaysOn != isEnabled) {
updateSummary(); mIsAlwaysOn = isEnabled;
updateSummary();
}
} }
/** /**

View File

@@ -34,7 +34,6 @@ import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.security.Credentials; import android.security.Credentials;
@@ -211,8 +210,8 @@ public class VpnSettings extends RestrictedSettingsFragment implements
final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore); final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore);
final List<AppVpnInfo> vpnApps = getVpnApps(getActivity(), /* includeProfiles */ true); final List<AppVpnInfo> vpnApps = getVpnApps(getActivity(), /* includeProfiles */ true);
final List<LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns(); final Map<String, LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns();
final List<AppVpnInfo> connectedAppVpns = getConnectedAppVpns(); final Set<AppVpnInfo> connectedAppVpns = getConnectedAppVpns();
final Set<AppVpnInfo> alwaysOnAppVpnInfos = getAlwaysOnAppVpnInfos(); final Set<AppVpnInfo> alwaysOnAppVpnInfos = getAlwaysOnAppVpnInfos();
final String lockdownVpnKey = VpnUtils.getLockdownVpn(); final String lockdownVpnKey = VpnUtils.getLockdownVpn();
@@ -231,18 +230,26 @@ public class VpnSettings extends RestrictedSettingsFragment implements
for (VpnProfile profile : vpnProfiles) { for (VpnProfile profile : vpnProfiles) {
LegacyVpnPreference p = findOrCreatePreference(profile); LegacyVpnPreference p = findOrCreatePreference(profile);
p.setState(LegacyVpnPreference.STATE_NONE); if (connectedLegacyVpns.containsKey(profile.key)) {
p.setState(connectedLegacyVpns.get(profile.key).state);
} else {
p.setState(LegacyVpnPreference.STATE_NONE);
}
p.setAlwaysOn(lockdownVpnKey != null && lockdownVpnKey.equals(profile.key)); p.setAlwaysOn(lockdownVpnKey != null && lockdownVpnKey.equals(profile.key));
updates.add(p); updates.add(p);
} }
for (AppVpnInfo app : vpnApps) { for (AppVpnInfo app : vpnApps) {
AppPreference p = findOrCreatePreference(app); AppPreference p = findOrCreatePreference(app);
p.setState(AppPreference.STATE_DISCONNECTED); if (connectedAppVpns.contains(app)) {
p.setState(AppPreference.STATE_CONNECTED);
} else {
p.setState(AppPreference.STATE_DISCONNECTED);
}
p.setAlwaysOn(alwaysOnAppVpnInfos.contains(app)); p.setAlwaysOn(alwaysOnAppVpnInfos.contains(app));
updates.add(p); updates.add(p);
} }
// Trim preferences for deleted VPNs // Trim out deleted VPN preferences
mLegacyVpnPreferences.values().retainAll(updates); mLegacyVpnPreferences.values().retainAll(updates);
mAppPreferences.values().retainAll(updates); mAppPreferences.values().retainAll(updates);
@@ -260,20 +267,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
for (Preference pref : updates) { for (Preference pref : updates) {
vpnGroup.addPreference(pref); vpnGroup.addPreference(pref);
} }
// Mark connected VPNs
for (LegacyVpnInfo info : connectedLegacyVpns) {
final LegacyVpnPreference preference = mLegacyVpnPreferences.get(info.key);
if (preference != null) {
preference.setState(info.state);
}
}
for (AppVpnInfo app : connectedAppVpns) {
final AppPreference preference = mAppPreferences.get(app);
if (preference != null) {
preference.setState(AppPreference.STATE_CONNECTED);
}
}
} }
}); });
@@ -369,6 +362,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements
pref.setOnPreferenceClickListener(this); pref.setOnPreferenceClickListener(this);
mLegacyVpnPreferences.put(profile.key, pref); mLegacyVpnPreferences.put(profile.key, pref);
} }
// This may change as the profile can update and keep the same key.
pref.setProfile(profile); pref.setProfile(profile);
return pref; return pref;
} }
@@ -377,33 +371,31 @@ public class VpnSettings extends RestrictedSettingsFragment implements
private AppPreference findOrCreatePreference(AppVpnInfo app) { private AppPreference findOrCreatePreference(AppVpnInfo app) {
AppPreference pref = mAppPreferences.get(app); AppPreference pref = mAppPreferences.get(app);
if (pref == null) { if (pref == null) {
pref = new AppPreference(getPrefContext()); pref = new AppPreference(getPrefContext(), app.userId, app.packageName);
pref.setOnGearClickListener(mGearListener); pref.setOnGearClickListener(mGearListener);
pref.setOnPreferenceClickListener(this); pref.setOnPreferenceClickListener(this);
mAppPreferences.put(app, pref); mAppPreferences.put(app, pref);
} }
pref.setUserId(app.userId);
pref.setPackageName(app.packageName);
return pref; return pref;
} }
@WorkerThread @WorkerThread
private List<LegacyVpnInfo> getConnectedLegacyVpns() { private Map<String, LegacyVpnInfo> getConnectedLegacyVpns() {
try { try {
mConnectedLegacyVpn = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId()); mConnectedLegacyVpn = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId());
if (mConnectedLegacyVpn != null) { if (mConnectedLegacyVpn != null) {
return Collections.singletonList(mConnectedLegacyVpn); return Collections.singletonMap(mConnectedLegacyVpn.key, mConnectedLegacyVpn);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, "Failure updating VPN list with connected legacy VPNs", e); Log.e(LOG_TAG, "Failure updating VPN list with connected legacy VPNs", e);
} }
return Collections.emptyList(); return Collections.emptyMap();
} }
@WorkerThread @WorkerThread
private List<AppVpnInfo> getConnectedAppVpns() { private Set<AppVpnInfo> getConnectedAppVpns() {
// Mark connected third-party services // Mark connected third-party services
List<AppVpnInfo> connections = new ArrayList<>(); Set<AppVpnInfo> connections = new ArraySet<>();
try { try {
for (UserHandle profile : mUserManager.getUserProfiles()) { for (UserHandle profile : mUserManager.getUserProfiles()) {
VpnConfig config = mConnectivityService.getVpnConfig(profile.getIdentifier()); VpnConfig config = mConnectivityService.getVpnConfig(profile.getIdentifier());