release-request-cacfaf25-4304-4e6b-ab4e-089367c7ed39-for-git_pi-release-4326570 snap-temp-L59400000101056305

Change-Id: Ifac37339de26f970d5519942dc46ded5a507bcda
This commit is contained in:
android-build-team Robot
2017-09-10 08:15:25 +00:00
38 changed files with 1799 additions and 852 deletions

View File

@@ -9066,4 +9066,11 @@
<!-- Note displayed when certain features are not available on low ram devices. [CHAR LIMIT=NONE] -->
<string name="disabled_low_ram_device">This feature is not available on this device</string>
<!--Label of IMS registration header -->
<string name="ims_reg_title">"IMS registration state"</string>
<!--Used when IMS registration state is registered -->
<string name="ims_reg_status_registered">"Registered"</string>
<!--Used when IMS registration state is not registered -->
<string name="ims_reg_status_not_registered">"Not registered"</string>
</resources>

View File

@@ -89,4 +89,10 @@
android:title="@string/status_wimax_mac_address"
android:summary="@string/device_info_not_available"
android:persistent="false" />
<Preference
android:key="ims_reg_state"
android:enabled="false"
android:shouldDisableView="false"
android:title="@string/ims_reg_title"
android:persistent="false" />
</PreferenceScreen>

View File

@@ -61,6 +61,7 @@ import android.widget.Switch;
import android.widget.TabHost;
import android.widget.TextView;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
@@ -152,6 +153,7 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment
private int mConfirmingCredentialUser;
private IntConsumer mConfirmingCredentialListener;
private Set<AdapterData.AliasLoader> mAliasLoaders = new ArraySet<AdapterData.AliasLoader>(2);
@GuardedBy("mKeyChainConnectionByProfileId")
private final SparseArray<KeyChainConnection>
mKeyChainConnectionByProfileId = new SparseArray<KeyChainConnection>();
@@ -256,11 +258,13 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment
}
private void closeKeyChainConnections() {
final int n = mKeyChainConnectionByProfileId.size();
for (int i = 0; i < n; ++i) {
mKeyChainConnectionByProfileId.valueAt(i).close();
synchronized (mKeyChainConnectionByProfileId) {
final int n = mKeyChainConnectionByProfileId.size();
for (int i = 0; i < n; ++i) {
mKeyChainConnectionByProfileId.valueAt(i).close();
}
mKeyChainConnectionByProfileId.clear();
}
mKeyChainConnectionByProfileId.clear();
}
private void addTab(Tab tab) {
@@ -684,62 +688,64 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment
SparseArray<List<CertHolder>> certHoldersByProfile =
new SparseArray<List<CertHolder>>();
try {
List<UserHandle> profiles = mUserManager.getUserProfiles();
final int n = profiles.size();
// First we get all aliases for all profiles in order to show progress
// correctly. Otherwise this could all be in a single loop.
SparseArray<List<String>> aliasesByProfileId = new SparseArray<
List<String>>(n);
int max = 0;
int progress = 0;
for (int i = 0; i < n; ++i) {
UserHandle profile = profiles.get(i);
int profileId = profile.getIdentifier();
if (shouldSkipProfile(profile)) {
continue;
synchronized(mKeyChainConnectionByProfileId) {
List<UserHandle> profiles = mUserManager.getUserProfiles();
final int n = profiles.size();
// First we get all aliases for all profiles in order to show progress
// correctly. Otherwise this could all be in a single loop.
SparseArray<List<String>> aliasesByProfileId = new SparseArray<
List<String>>(n);
int max = 0;
int progress = 0;
for (int i = 0; i < n; ++i) {
UserHandle profile = profiles.get(i);
int profileId = profile.getIdentifier();
if (shouldSkipProfile(profile)) {
continue;
}
KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext,
profile);
// Saving the connection for later use on the certificate dialog.
mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
IKeyChainService service = keyChainConnection.getService();
List<String> aliases = mTab.getAliases(service);
if (isCancelled()) {
return new SparseArray<List<CertHolder>>();
}
max += aliases.size();
aliasesByProfileId.put(profileId, aliases);
}
KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext,
profile);
// Saving the connection for later use on the certificate dialog.
mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
IKeyChainService service = keyChainConnection.getService();
List<String> aliases = mTab.getAliases(service);
if (isCancelled()) {
return new SparseArray<List<CertHolder>>();
for (int i = 0; i < n; ++i) {
UserHandle profile = profiles.get(i);
int profileId = profile.getIdentifier();
List<String> aliases = aliasesByProfileId.get(profileId);
if (isCancelled()) {
return new SparseArray<List<CertHolder>>();
}
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
profileId);
if (shouldSkipProfile(profile) || aliases == null
|| keyChainConnection == null) {
certHoldersByProfile.put(profileId, new ArrayList<CertHolder>(0));
continue;
}
IKeyChainService service = keyChainConnection.getService();
List<CertHolder> certHolders = new ArrayList<CertHolder>(max);
final int aliasMax = aliases.size();
for (int j = 0; j < aliasMax; ++j) {
String alias = aliases.get(j);
byte[] encodedCertificate = service.getEncodedCaCertificate(alias,
true);
X509Certificate cert = KeyChain.toCertificate(encodedCertificate);
certHolders.add(new CertHolder(service, mAdapter,
mTab, alias, cert, profileId));
publishProgress(++progress, max);
}
Collections.sort(certHolders);
certHoldersByProfile.put(profileId, certHolders);
}
max += aliases.size();
aliasesByProfileId.put(profileId, aliases);
return certHoldersByProfile;
}
for (int i = 0; i < n; ++i) {
UserHandle profile = profiles.get(i);
int profileId = profile.getIdentifier();
List<String> aliases = aliasesByProfileId.get(profileId);
if (isCancelled()) {
return new SparseArray<List<CertHolder>>();
}
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
profileId);
if (shouldSkipProfile(profile) || aliases == null
|| keyChainConnection == null) {
certHoldersByProfile.put(profileId, new ArrayList<CertHolder>(0));
continue;
}
IKeyChainService service = keyChainConnection.getService();
List<CertHolder> certHolders = new ArrayList<CertHolder>(max);
final int aliasMax = aliases.size();
for (int j = 0; j < aliasMax; ++j) {
String alias = aliases.get(j);
byte[] encodedCertificate = service.getEncodedCaCertificate(alias,
true);
X509Certificate cert = KeyChain.toCertificate(encodedCertificate);
certHolders.add(new CertHolder(service, mAdapter,
mTab, alias, cert, profileId));
publishProgress(++progress, max);
}
Collections.sort(certHolders);
certHoldersByProfile.put(profileId, certHolders);
}
return certHoldersByProfile;
} catch (RemoteException e) {
Log.e(TAG, "Remote exception while loading aliases.", e);
return new SparseArray<List<CertHolder>>();
@@ -936,16 +942,18 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment
public List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder) {
List<X509Certificate> certificates = null;
try {
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
certHolder.mProfileId);
IKeyChainService service = keyChainConnection.getService();
List<String> chain = service.getCaCertificateChainAliases(certHolder.mAlias, true);
final int n = chain.size();
certificates = new ArrayList<X509Certificate>(n);
for (int i = 0; i < n; ++i) {
byte[] encodedCertificate = service.getEncodedCaCertificate(chain.get(i), true);
X509Certificate certificate = KeyChain.toCertificate(encodedCertificate);
certificates.add(certificate);
synchronized (mKeyChainConnectionByProfileId) {
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
certHolder.mProfileId);
IKeyChainService service = keyChainConnection.getService();
List<String> chain = service.getCaCertificateChainAliases(certHolder.mAlias, true);
final int n = chain.size();
certificates = new ArrayList<X509Certificate>(n);
for (int i = 0; i < n; ++i) {
byte[] encodedCertificate = service.getEncodedCaCertificate(chain.get(i), true);
X509Certificate certificate = KeyChain.toCertificate(encodedCertificate);
certificates.add(certificate);
}
}
} catch (RemoteException ex) {
Log.e(TAG, "RemoteException while retrieving certificate chain for root "
@@ -985,15 +993,17 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment
@Override
protected Boolean doInBackground(Void... params) {
try {
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
mCertHolder.mProfileId);
IKeyChainService service = keyChainConnection.getService();
if (mCertHolder.mDeleted) {
byte[] bytes = mCertHolder.mX509Cert.getEncoded();
service.installCaCertificate(bytes);
return true;
} else {
return service.deleteCaCertificate(mCertHolder.mAlias);
synchronized (mKeyChainConnectionByProfileId) {
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
mCertHolder.mProfileId);
IKeyChainService service = keyChainConnection.getService();
if (mCertHolder.mDeleted) {
byte[] bytes = mCertHolder.mX509Cert.getEncoded();
service.installCaCertificate(bytes);
return true;
} else {
return service.deleteCaCertificate(mCertHolder.mAlias);
}
}
} catch (CertificateEncodingException | SecurityException | IllegalStateException
| RemoteException e) {

View File

@@ -188,22 +188,27 @@ public final class BluetoothDevicePreference extends GearPreference implements
}
void onClicked() {
Context context = getContext();
int bondState = mCachedDevice.getBondState();
final MetricsFeatureProvider metricsFeatureProvider =
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider();
FeatureFactory.getFactory(context).getMetricsFeatureProvider();
if (mCachedDevice.isConnected()) {
metricsFeatureProvider.action(getContext(),
metricsFeatureProvider.action(context,
MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
askDisconnect();
} else if (bondState == BluetoothDevice.BOND_BONDED) {
metricsFeatureProvider.action(getContext(),
metricsFeatureProvider.action(context,
MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT);
mCachedDevice.connect(true);
} else if (bondState == BluetoothDevice.BOND_NONE) {
metricsFeatureProvider.action(getContext(),
metricsFeatureProvider.action(context,
MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
if (!mCachedDevice.hasHumanReadableName()) {
metricsFeatureProvider.action(context,
MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
}
pair();
}
}

View File

@@ -94,19 +94,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
}
};
private View.OnClickListener mConditionClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Condition condition = (Condition) v.getTag();
//TODO: get rid of setTag/getTag
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
condition.getMetricsConstant());
condition.onPrimaryClick();
}
};
public DashboardAdapter(Context context, Bundle savedInstanceState,
List<Condition> conditions, SuggestionParser suggestionParser,
SuggestionDismissController.Callback callback) {
@@ -129,7 +116,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
suggestions = savedInstanceState.getParcelableArrayList(STATE_SUGGESTION_LIST);
category = savedInstanceState.getParcelable(STATE_CATEGORY_LIST);
suggestionConditionMode = savedInstanceState.getInt(
STATE_SUGGESTION_CONDITION_MODE, suggestionConditionMode);
STATE_SUGGESTION_CONDITION_MODE, suggestionConditionMode);
mSuggestionsShownLogged = savedInstanceState.getStringArrayList(
STATE_SUGGESTIONS_SHOWN_LOGGED);
} else {
@@ -249,7 +236,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
break;
case R.layout.suggestion_condition_container:
onBindConditionAndSuggestion(
(SuggestionAndConditionContainerHolder) holder, position);
(SuggestionAndConditionContainerHolder) holder, position);
break;
case R.layout.suggestion_condition_header:
onBindSuggestionConditionHeader((SuggestionAndConditionHeaderHolder) holder,
@@ -262,7 +249,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, false);
DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData).setSuggestionConditionMode(
DashboardData.HEADER_MODE_COLLAPSED).build();
DashboardData.HEADER_MODE_COLLAPSED).build();
notifyDashboardDataChanged(prevData);
mRecyclerView.scrollToPosition(SUGGESTION_CONDITION_HEADER_POSITION);
});
@@ -335,11 +322,11 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
}
for (Tile suggestion : suggestions) {
final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
mContext, suggestion);
mContext, suggestion);
if (!mSuggestionsShownLogged.contains(suggestionId)) {
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
suggestionId);
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
suggestionId);
mSuggestionsShownLogged.add(suggestionId);
}
}
@@ -350,9 +337,9 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
SuggestionConditionHeaderData data) {
final int curMode = mDashboardData.getSuggestionConditionMode();
final int nextMode = data.hiddenSuggestionCount > 0 && data.conditionCount > 0
&& curMode != DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
? DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
: DashboardData.HEADER_MODE_FULLY_EXPANDED;
&& curMode != DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
? DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
: DashboardData.HEADER_MODE_FULLY_EXPANDED;
final boolean moreSuggestions = data.hiddenSuggestionCount > 0;
final boolean hasConditions = data.conditionCount > 0;
if (data.conditionCount > 0) {
@@ -377,22 +364,22 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
if (curMode == DashboardData.HEADER_MODE_COLLAPSED) {
if (data.conditionCount > 0) {
holder.summary.setText(mContext.getResources().getQuantityString(
R.plurals.suggestions_collapsed_summary,
data.hiddenSuggestionCount, data.hiddenSuggestionCount));
R.plurals.suggestions_collapsed_summary,
data.hiddenSuggestionCount, data.hiddenSuggestionCount));
} else {
holder.title.setText(mContext.getResources().getQuantityString(
R.plurals.suggestions_collapsed_title,
data.hiddenSuggestionCount, data.hiddenSuggestionCount));
R.plurals.suggestions_collapsed_title,
data.hiddenSuggestionCount, data.hiddenSuggestionCount));
holder.title.setTextColor(Color.BLACK);
holder.summary.setText(null);
}
} else if (curMode == DashboardData.HEADER_MODE_DEFAULT) {
if (data.conditionCount > 0) {
holder.summary.setText(mContext.getString(
R.string.suggestions_summary, data.hiddenSuggestionCount));
R.string.suggestions_summary, data.hiddenSuggestionCount));
} else {
holder.title.setText(mContext.getString(
R.string.suggestions_more_title, data.hiddenSuggestionCount));
R.string.suggestions_more_title, data.hiddenSuggestionCount));
holder.title.setTextColor(Color.BLACK);
holder.summary.setText(null);
}
@@ -400,7 +387,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
} else if (data.conditionCount > 1) {
holder.summary.setTextColor(Utils.getColorAccent(mContext));
holder.summary.setText(
mContext.getString(R.string.condition_summary, data.conditionCount));
mContext.getString(R.string.condition_summary, data.conditionCount));
} else {
holder.summary.setText(null);
}
@@ -413,16 +400,16 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
holder.itemView.setPadding(0, padding, 0, padding);
holder.itemView.setOnClickListener(v -> {
if (moreSuggestions ) {
if (moreSuggestions) {
logSuggestions();
} else if (hasConditions) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, true);
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, true);
}
DashboardData prevData = mDashboardData;
final boolean wasCollapsed = curMode == DashboardData.HEADER_MODE_COLLAPSED;
mDashboardData = new DashboardData.Builder(prevData)
.setSuggestionConditionMode(nextMode).build();
.setSuggestionConditionMode(nextMode).build();
notifyDashboardDataChanged(prevData);
if (wasCollapsed) {
mRecyclerView.scrollToPosition(SUGGESTION_CONDITION_HEADER_POSITION);
@@ -439,13 +426,13 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
if (position == SUGGESTION_CONDITION_HEADER_POSITION
&& suggestions != null && suggestions.size() > 0) {
mSuggestionAdapter = new SuggestionAdapter(mContext, (List<Tile>)
mDashboardData.getItemEntityByPosition(position), mSuggestionsShownLogged);
mDashboardData.getItemEntityByPosition(position), mSuggestionsShownLogged);
mSuggestionDismissHandler = new SuggestionDismissController(mContext,
holder.data, mSuggestionParser, mCallback);
holder.data, mSuggestionParser, mCallback);
holder.data.setAdapter(mSuggestionAdapter);
} else {
ConditionAdapter adapter = new ConditionAdapter(mContext,
(List<Condition>) mDashboardData.getItemEntityByPosition(position),
(List<Condition>) mDashboardData.getItemEntityByPosition(position),
mDashboardData.getSuggestionConditionMode());
adapter.addDismissHandling(holder.data);
holder.data.setAdapter(adapter);
@@ -454,19 +441,13 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
}
private void onBindTile(DashboardItemHolder holder, Tile tile) {
if (tile.remoteViews != null) {
final ViewGroup itemView = (ViewGroup) holder.itemView;
itemView.removeAllViews();
itemView.addView(tile.remoteViews.apply(itemView.getContext(), itemView));
holder.icon.setImageDrawable(mCache.getIcon(tile.icon));
holder.title.setText(tile.title);
if (!TextUtils.isEmpty(tile.summary)) {
holder.summary.setText(tile.summary);
holder.summary.setVisibility(View.VISIBLE);
} else {
holder.icon.setImageDrawable(mCache.getIcon(tile.icon));
holder.title.setText(tile.title);
if (!TextUtils.isEmpty(tile.summary)) {
holder.summary.setText(tile.summary);
holder.summary.setVisibility(View.VISIBLE);
} else {
holder.summary.setVisibility(View.GONE);
}
holder.summary.setVisibility(View.GONE);
}
}
@@ -507,7 +488,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
}
outState.putStringArrayList(STATE_SUGGESTIONS_SHOWN_LOGGED, mSuggestionsShownLogged);
outState.putInt(STATE_SUGGESTION_CONDITION_MODE,
mDashboardData.getSuggestionConditionMode());
mDashboardData.getSuggestionConditionMode());
}
private void updateConditionIcons(List<Icon> icons, ViewGroup parent) {
@@ -519,7 +500,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
parent.removeAllViews();
for (int i = 1, size = icons.size(); i < size; i++) {
ImageView icon = (ImageView) inflater.inflate(
R.layout.condition_header_icon, parent, false);
R.layout.condition_header_icon, parent, false);
icon.setImageIcon(icons.get(i));
parent.addView(icon);
}

View File

@@ -171,30 +171,6 @@ public class DashboardData {
return POSITION_NOT_FOUND;
}
/**
* Get the count of suggestions to display
*
* The displayable count mainly depends on the {@link #mSuggestionConditionMode}
* and the size of suggestions list.
*
* When in default mode, displayable count couldn't be larger than
* {@link #DEFAULT_SUGGESTION_COUNT}.
*
* When in expanded mode, display all the suggestions.
*
* @return the count of suggestions to display
*/
public int getDisplayableSuggestionCount() {
final int suggestionSize = sizeOf(mSuggestions);
if (mSuggestionConditionMode == HEADER_MODE_COLLAPSED) {
return 0;
}
if (mSuggestionConditionMode == HEADER_MODE_DEFAULT) {
return Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize);
}
return suggestionSize;
}
/**
* Add item into list when {@paramref add} is true.
*
@@ -280,7 +256,7 @@ public class DashboardData {
if (conditions == null) {
return null;
}
List<Condition> result = new ArrayList<Condition>();
List<Condition> result = new ArrayList<>();
final int size = conditions == null ? 0 : conditions.size();
for (int i = 0; i < size; i++) {
final Condition condition = conditions.get(i);
@@ -460,6 +436,17 @@ public class DashboardData {
// Only check title and summary for dashboard tile
return TextUtils.equals(localTile.title, targetTile.title)
&& TextUtils.equals(localTile.summary, targetTile.summary);
case TYPE_SUGGESTION_CONDITION_CONTAINER:
// If entity is suggestion and contains remote view, force refresh
final List entities = (List) entity;
if (!entities.isEmpty()) {
Object firstEntity = entities.get(0);
if (firstEntity instanceof Tile
&& ((Tile) firstEntity).remoteViews != null) {
return false;
}
}
// Otherwise Fall through to default
default:
return entity == null ? targetItem.entity == null
: entity.equals(targetItem.entity);
@@ -482,7 +469,7 @@ public class DashboardData {
conditionCount = sizeOf(conditions);
this.hiddenSuggestionCount = hiddenSuggestionCount;
title = conditionCount > 0 ? conditions.get(0).getTitle() : null;
conditionIcons = new ArrayList<Icon>();
conditionIcons = new ArrayList<>();
for (int i = 0; conditions != null && i < conditions.size(); i++) {
final Condition condition = conditions.get(i);
conditionIcons.add(condition.getIcon());

View File

@@ -230,6 +230,9 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
@VisibleForTesting
boolean tintTileIcon(Tile tile) {
if (tile.icon == null) {
return false;
}
// First check if the tile has set the icon tintable metadata.
final Bundle metadata = tile.metaData;
if (metadata != null

View File

@@ -29,6 +29,8 @@ import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
import com.android.settings.dashboard.DashboardAdapter.IconCache;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
import java.util.List;
import java.util.Objects;
@@ -73,6 +75,7 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
mSuggestionsShownLogged.add(suggestionId);
}
if (suggestion.remoteViews != null) {
TileUtils.updateTileUsingSummaryUri(mContext, suggestion);
final ViewGroup itemView = (ViewGroup) holder.itemView;
itemView.removeAllViews();
itemView.addView(suggestion.remoteViews.apply(itemView.getContext(), itemView));

View File

@@ -0,0 +1,76 @@
/**
* Copyright (C) 2017 The Android Open Source Project
*
* <p>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
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.deletionhelper;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
/**
* Handles the wall of text which appears below the options in the Storage Management settings drill
* down.
*/
public class AutomaticStorageManagerDescriptionPreferenceController
extends AbstractPreferenceController implements PreferenceControllerMixin {
private static final String KEY_FREED = "freed_bytes";
public AutomaticStorageManagerDescriptionPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY_FREED;
}
@Override
public void displayPreference(PreferenceScreen screen) {
Preference preference = screen.findPreference(getPreferenceKey());
final Context context = preference.getContext();
ContentResolver cr = context.getContentResolver();
long freedBytes =
Settings.Secure.getLong(
cr, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED, 0);
long lastRunMillis =
Settings.Secure.getLong(cr, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN, 0);
if (freedBytes == 0 || lastRunMillis == 0 || !isStorageManagerEnabled(cr)) {
preference.setSummary(R.string.automatic_storage_manager_text);
} else {
preference.setSummary(
context.getString(
R.string.automatic_storage_manager_freed_bytes,
Formatter.formatFileSize(context, freedBytes),
DateUtils.formatDateTime(
context, lastRunMillis, DateUtils.FORMAT_SHOW_DATE)));
}
}
private boolean isStorageManagerEnabled(ContentResolver cr) {
return Settings.Secure.getInt(cr, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 0)
!= 0;
}
}

View File

@@ -16,15 +16,13 @@
package com.android.settings.deletionhelper;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.preference.DropDownPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -32,39 +30,34 @@ import android.view.ViewGroup;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.List;
/**
* AutomaticStorageManagerSettings is the Settings screen for configuration and management of the
* automatic storage manager.
*/
public class AutomaticStorageManagerSettings extends SettingsPreferenceFragment
public class AutomaticStorageManagerSettings extends DashboardFragment
implements OnPreferenceChangeListener {
private static final String KEY_DAYS = "days";
private static final String KEY_FREED = "freed_bytes";
private static final String STORAGE_MANAGER_ENABLED_BY_DEFAULT_PROPERTY =
"ro.storage_manager.enabled";
private AutomaticStorageManagerSwitchBarController mSwitchController;
private DropDownPreference mDaysToRetain;
private Preference mFreedBytes;
private SwitchBar mSwitchBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.automatic_storage_management_settings);
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
initializeDaysToRetainPreference();
initializeFreedBytesPreference();
initializeSwitchBar();
return view;
@@ -98,35 +91,25 @@ public class AutomaticStorageManagerSettings extends SettingsPreferenceFragment
getFragmentManager());
}
private void initializeFreedBytesPreference() {
ContentResolver cr = getContentResolver();
mFreedBytes = findPreference(KEY_FREED);
long freedBytes = Settings.Secure.getLong(cr,
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED,
0);
long lastRunMillis = Settings.Secure.getLong(cr,
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
0);
if (freedBytes == 0 || lastRunMillis == 0) {
mFreedBytes.setVisible(false);
} else {
final Activity activity = getActivity();
mFreedBytes.setSummary(
activity.getString(
R.string.automatic_storage_manager_freed_bytes,
Formatter.formatFileSize(activity, freedBytes),
DateUtils.formatDateTime(
activity, lastRunMillis, DateUtils.FORMAT_SHOW_DATE)));
}
}
@Override
public void onResume() {
super.onResume();
boolean isStorageManagerChecked =
Settings.Secure.getInt(getContentResolver(),
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 0) != 0;
mDaysToRetain.setEnabled(isStorageManagerChecked);
mDaysToRetain.setEnabled(isStorageManagerEnabled());
}
@Override
protected String getLogTag() {
return null;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.automatic_storage_management_settings;
}
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return buildPreferenceControllers(context);
}
@Override
@@ -168,4 +151,30 @@ public class AutomaticStorageManagerSettings extends SettingsPreferenceFragment
return indices.length - 1;
}
private boolean isStorageManagerEnabled() {
return Settings.Secure.getInt(
getContentResolver(), Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 0)
!= 0;
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new AutomaticStorageManagerDescriptionPreferenceController(context));
return controllers;
}
/** For Search. */
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
protected boolean isPageSearchEnabled(Context context) {
return false;
}
@Override
public List<AbstractPreferenceController> getPreferenceControllers(
Context context) {
return buildPreferenceControllers(context);
}
};
}

View File

@@ -53,6 +53,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.provider.SearchIndexableResource;
@@ -1029,8 +1030,19 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
return context.getSystemService(Context.OEM_LOCK_SERVICE) != null;
}
/**
* Returns whether OEM unlock is allowed by the user and carrier.
*
* This does not take into account any restrictions imposed by the device policy.
*/
private boolean isOemUnlockAllowedByUserAndCarrier() {
final UserHandle userHandle = UserHandle.of(UserHandle.myUserId());
return mOemLockManager.isOemUnlockAllowedByCarrier()
&& !mUm.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET, userHandle);
}
private boolean enableOemUnlockPreference() {
return !isBootloaderUnlocked() && mOemLockManager.canUserAllowOemUnlock();
return !isBootloaderUnlocked() && isOemUnlockAllowedByUserAndCarrier();
}
private void updateOemUnlockOptions() {
@@ -1044,10 +1056,6 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
// Check restriction, disable mEnableOemUnlock and apply policy transparency.
mEnableOemUnlock.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET);
}
if (mEnableOemUnlock.isEnabled()) {
// Check restriction, disable mEnableOemUnlock and apply policy transparency.
mEnableOemUnlock.checkRestrictionAndSetDisabled(UserManager.DISALLOW_OEM_UNLOCK);
}
}
}
@@ -2572,7 +2580,7 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_bootloader_unlocked;
} else if (isSimLockedDevice()) {
oemUnlockSummary = R.string.oem_unlock_enable_disabled_summary_sim_locked_device;
} else if (!mOemLockManager.canUserAllowOemUnlock()) {
} else if (!isOemUnlockAllowedByUserAndCarrier()) {
// If the device isn't SIM-locked but OEM unlock is disallowed by some party, this
// means either some other carrier restriction is in place or the device hasn't been
// able to confirm which restrictions (SIM-lock or otherwise) apply.

View File

@@ -28,11 +28,15 @@ import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -56,6 +60,7 @@ public class Status extends SettingsPreferenceFragment {
private static final String KEY_WIMAX_MAC_ADDRESS = "wimax_mac_address";
private static final String KEY_SIM_STATUS = "sim_status";
private static final String KEY_IMEI_INFO = "imei_info";
private static final String KEY_IMS_REGISTRATION_STATE = "ims_reg_state";
// Broadcasts to listen to for connectivity changes.
private static final String[] CONNECTIVITY_INTENTS = {
@@ -85,6 +90,8 @@ public class Status extends SettingsPreferenceFragment {
private Preference mIpAddress;
private Preference mWifiMacAddress;
private Preference mWimaxMacAddress;
private Preference mImsStatus;
private Handler mHandler;
private static class MyHandler extends Handler {
@@ -162,6 +169,7 @@ public class Status extends SettingsPreferenceFragment {
mWifiMacAddress = findPreference(KEY_WIFI_MAC_ADDRESS);
mWimaxMacAddress = findPreference(KEY_WIMAX_MAC_ADDRESS);
mIpAddress = findPreference(KEY_IP_ADDRESS);
mImsStatus = findPreference(KEY_IMS_REGISTRATION_STATE);
mRes = getResources();
mUnavailable = mRes.getString(R.string.status_unavailable);
@@ -269,11 +277,31 @@ public class Status extends SettingsPreferenceFragment {
}
}
private void setImsRegistrationStatus() {
CarrierConfigManager configManager = (CarrierConfigManager)
getSystemService(Context.CARRIER_CONFIG_SERVICE);
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
PersistableBundle config = null;
if (configManager != null) {
config = configManager.getConfigForSubId(subId);
}
if (config != null && config.getBoolean(
CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL)) {
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
mImsStatus.setSummary((tm != null && tm.isImsRegistered(subId)) ?
R.string.ims_reg_status_registered : R.string.ims_reg_status_not_registered);
} else {
removePreferenceFromScreen(KEY_IMS_REGISTRATION_STATE);
mImsStatus = null;
}
}
void updateConnectivity() {
setWimaxStatus();
setWifiStatus();
setBtStatus();
setIpAddressStatus();
setImsRegistrationStatus();
}
void updateTimes() {

View File

@@ -40,6 +40,7 @@ import com.android.settings.applications.UserManagerWrapper;
import com.android.settings.applications.UserManagerWrapperImpl;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController;
import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper;
import com.android.settings.deviceinfo.storage.SecondaryUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
@@ -68,6 +69,7 @@ public class StorageDashboardFragment extends DashboardFragment
private VolumeInfo mVolume;
private PrivateStorageInfo mStorageInfo;
private SparseArray<StorageAsyncLoader.AppsStorageResult> mAppsResult;
private CachedStorageValuesHelper mCachedStorageValuesHelper;
private StorageSummaryDonutPreferenceController mSummaryController;
private StorageItemPreferenceController mPreferenceController;
@@ -102,7 +104,10 @@ public class StorageDashboardFragment extends DashboardFragment
@Override
public void onViewCreated(View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
setLoading(true, false);
initializeCacheProvider();
if (mAppsResult == null || mStorageInfo == null) {
setLoading(true, false);
}
}
@Override
@@ -249,6 +254,7 @@ public class StorageDashboardFragment extends DashboardFragment
public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader,
SparseArray<StorageAsyncLoader.AppsStorageResult> data) {
mAppsResult = data;
maybeCacheFreshValues();
onReceivedSizes();
}
@@ -256,6 +262,48 @@ public class StorageDashboardFragment extends DashboardFragment
public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) {
}
@VisibleForTesting
public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) {
mCachedStorageValuesHelper = helper;
}
@VisibleForTesting
public PrivateStorageInfo getPrivateStorageInfo() {
return mStorageInfo;
}
@VisibleForTesting
public SparseArray<StorageAsyncLoader.AppsStorageResult> getAppsStorageResult() {
return mAppsResult;
}
@VisibleForTesting
public void initializeCachedValues() {
PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo();
SparseArray<StorageAsyncLoader.AppsStorageResult> loaderResult =
mCachedStorageValuesHelper.getCachedAppsStorageResult();
if (info == null || loaderResult == null) {
return;
}
mStorageInfo = info;
mAppsResult = loaderResult;
}
private void initializeCacheProvider() {
mCachedStorageValuesHelper =
new CachedStorageValuesHelper(getContext(), UserHandle.myUserId());
initializeCachedValues();
onReceivedSizes();
}
private void maybeCacheFreshValues() {
if (mStorageInfo != null && mAppsResult != null) {
mCachedStorageValuesHelper.cacheResult(
mStorageInfo, mAppsResult.get(UserHandle.myUserId()));
}
}
/**
* IconLoaderCallbacks exists because StorageDashboardFragment already implements
* LoaderCallbacks for a different type.
@@ -308,6 +356,7 @@ public class StorageDashboardFragment extends DashboardFragment
}
mStorageInfo = privateStorageInfo;
maybeCacheFreshValues();
onReceivedSizes();
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (C) 2017 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.deviceinfo.storage;
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.util.SparseArray;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import java.util.concurrent.TimeUnit;
public class CachedStorageValuesHelper {
@VisibleForTesting public static final String SHARED_PREFERENCES_NAME = "CachedStorageValues";
public static final String TIMESTAMP_KEY = "last_query_timestamp";
public static final String FREE_BYTES_KEY = "free_bytes";
public static final String TOTAL_BYTES_KEY = "total_bytes";
public static final String GAME_APPS_SIZE_KEY = "game_apps_size";
public static final String MUSIC_APPS_SIZE_KEY = "music_apps_size";
public static final String VIDEO_APPS_SIZE_KEY = "video_apps_size";
public static final String PHOTO_APPS_SIZE_KEY = "photo_apps_size";
public static final String OTHER_APPS_SIZE_KEY = "other_apps_size";
public static final String CACHE_APPS_SIZE_KEY = "cache_apps_size";
public static final String EXTERNAL_TOTAL_BYTES = "external_total_bytes";
public static final String EXTERNAL_AUDIO_BYTES = "external_audio_bytes";
public static final String EXTERNAL_VIDEO_BYTES = "external_video_bytes";
public static final String EXTERNAL_IMAGE_BYTES = "external_image_bytes";
public static final String EXTERNAL_APP_BYTES = "external_apps_bytes";
public static final String USER_ID_KEY = "user_id";
private final Long mClobberThreshold;
private final SharedPreferences mSharedPreferences;
private final int mUserId;
// This clock is used to provide the time. By default, it uses the system clock, but can be
// replaced for test purposes.
protected Clock mClock;
public CachedStorageValuesHelper(Context context, int userId) {
mSharedPreferences =
context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
mClock = new Clock();
mUserId = userId;
mClobberThreshold =
Settings.Global.getLong(
context.getContentResolver(),
Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
TimeUnit.MINUTES.toMillis(5));
}
public PrivateStorageInfo getCachedPrivateStorageInfo() {
if (!isDataValid()) {
return null;
}
final long freeBytes = mSharedPreferences.getLong(FREE_BYTES_KEY, -1);
final long totalBytes = mSharedPreferences.getLong(TOTAL_BYTES_KEY, -1);
if (freeBytes < 0 || totalBytes < 0) {
return null;
}
return new PrivateStorageInfo(freeBytes, totalBytes);
}
public SparseArray<StorageAsyncLoader.AppsStorageResult> getCachedAppsStorageResult() {
if (!isDataValid()) {
return null;
}
final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1);
final long musicAppsSize = mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1);
final long videoAppsSize = mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1);
final long photoAppSize = mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1);
final long otherAppsSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1);
final long cacheSize = mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1);
if (gamesSize < 0
|| musicAppsSize < 0
|| videoAppsSize < 0
|| photoAppSize < 0
|| otherAppsSize < 0
|| cacheSize < 0) {
return null;
}
final long externalTotalBytes = mSharedPreferences.getLong(EXTERNAL_TOTAL_BYTES, -1);
final long externalAudioBytes = mSharedPreferences.getLong(EXTERNAL_AUDIO_BYTES, -1);
final long externalVideoBytes = mSharedPreferences.getLong(EXTERNAL_VIDEO_BYTES, -1);
final long externalImageBytes = mSharedPreferences.getLong(EXTERNAL_IMAGE_BYTES, -1);
final long externalAppBytes = mSharedPreferences.getLong(EXTERNAL_APP_BYTES, -1);
if (externalTotalBytes < 0
|| externalAudioBytes < 0
|| externalVideoBytes < 0
|| externalImageBytes < 0
|| externalAppBytes < 0) {
return null;
}
final StorageStatsSource.ExternalStorageStats externalStats =
new StorageStatsSource.ExternalStorageStats(
externalTotalBytes,
externalAudioBytes,
externalVideoBytes,
externalImageBytes,
externalAppBytes);
final StorageAsyncLoader.AppsStorageResult result =
new StorageAsyncLoader.AppsStorageResult();
result.gamesSize = gamesSize;
result.musicAppsSize = musicAppsSize;
result.videoAppsSize = videoAppsSize;
result.photosAppsSize = photoAppSize;
result.otherAppsSize = otherAppsSize;
result.cacheSize = cacheSize;
result.externalStats = externalStats;
final SparseArray<StorageAsyncLoader.AppsStorageResult> resultArray = new SparseArray<>();
resultArray.append(mUserId, result);
return resultArray;
}
public void cacheResult(
PrivateStorageInfo storageInfo, StorageAsyncLoader.AppsStorageResult result) {
mSharedPreferences
.edit()
.putLong(FREE_BYTES_KEY, storageInfo.freeBytes)
.putLong(TOTAL_BYTES_KEY, storageInfo.totalBytes)
.putLong(GAME_APPS_SIZE_KEY, result.gamesSize)
.putLong(MUSIC_APPS_SIZE_KEY, result.musicAppsSize)
.putLong(VIDEO_APPS_SIZE_KEY, result.videoAppsSize)
.putLong(PHOTO_APPS_SIZE_KEY, result.photosAppsSize)
.putLong(OTHER_APPS_SIZE_KEY, result.otherAppsSize)
.putLong(CACHE_APPS_SIZE_KEY, result.cacheSize)
.putLong(EXTERNAL_TOTAL_BYTES, result.externalStats.totalBytes)
.putLong(EXTERNAL_AUDIO_BYTES, result.externalStats.audioBytes)
.putLong(EXTERNAL_VIDEO_BYTES, result.externalStats.videoBytes)
.putLong(EXTERNAL_IMAGE_BYTES, result.externalStats.imageBytes)
.putLong(EXTERNAL_APP_BYTES, result.externalStats.appBytes)
.putInt(USER_ID_KEY, mUserId)
.putLong(TIMESTAMP_KEY, mClock.getCurrentTime())
.apply();
}
private boolean isDataValid() {
final int cachedUserId = mSharedPreferences.getInt(USER_ID_KEY, -1);
if (cachedUserId != mUserId) {
return false;
}
final long lastQueryTime = mSharedPreferences.getLong(TIMESTAMP_KEY, Long.MAX_VALUE);
final long currentTime = mClock.getCurrentTime();
return currentTime - lastQueryTime < mClobberThreshold;
}
/** Clock provides the current time. */
static class Clock {
public long getCurrentTime() {
return System.currentTimeMillis();
}
}
}

View File

@@ -208,23 +208,18 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
public void setUserId(UserHandle userHandle) {
mUserId = userHandle.getIdentifier();
PackageManager pm = mContext.getPackageManager();
badgePreference(pm, userHandle, mPhotoPreference);
badgePreference(pm, userHandle, mMoviesPreference);
badgePreference(pm, userHandle, mAudioPreference);
badgePreference(pm, userHandle, mGamePreference);
badgePreference(pm, userHandle, mAppPreference);
badgePreference(pm, userHandle, mSystemPreference);
badgePreference(pm, userHandle, mFilePreference);
tintPreference(mPhotoPreference);
tintPreference(mMoviesPreference);
tintPreference(mAudioPreference);
tintPreference(mGamePreference);
tintPreference(mAppPreference);
tintPreference(mSystemPreference);
tintPreference(mFilePreference);
}
private void badgePreference(PackageManager pm, UserHandle userHandle, Preference preference) {
private void tintPreference(Preference preference) {
if (preference != null) {
Drawable currentIcon = preference.getIcon();
// Sigh... Applying the badge to the icon clobbers the tint on the base drawable.
// For some reason, reapplying it here means the tint remains.
currentIcon = applyTint(mContext, currentIcon);
preference.setIcon(pm.getUserBadgedIcon(currentIcon, userHandle));
preference.setIcon(applyTint(mContext, preference.getIcon()));
}
}

View File

@@ -17,27 +17,6 @@
package com.android.settings.search;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ENTRIES;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEY;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEYWORDS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SCREEN_TITLE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_OFF;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_TITLE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_USER_ID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_ID;
import static com.android.settings.search.DatabaseResultLoader
.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
@@ -70,17 +49,14 @@ import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.USER_
import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.provider.SearchIndexableData;
@@ -89,7 +65,6 @@ import android.provider.SearchIndexablesContract;
import android.support.annotation.DrawableRes;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -98,13 +73,13 @@ import com.android.settings.SettingsActivity;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.indexing.IndexableDataCollector;
import com.android.settings.search.indexing.PreIndexData;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -132,23 +107,14 @@ public class DatabaseIndexingManager {
private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
private static final List<String> EMPTY_LIST = Collections.emptyList();
private final String mBaseAuthority;
@VisibleForTesting
final AtomicBoolean mIsIndexingComplete = new AtomicBoolean(false);
@VisibleForTesting
final UpdateData mDataToProcess = new UpdateData();
private IndexableDataCollector mCollector;
private Context mContext;
public DatabaseIndexingManager(Context context, String baseAuthority) {
mContext = context;
mBaseAuthority = baseAuthority;
}
public void setContext(Context context) {
public DatabaseIndexingManager(Context context) {
mContext = context;
}
@@ -177,33 +143,17 @@ public class DatabaseIndexingManager {
final String providerVersionedNames =
IndexDatabaseHelper.buildProviderVersionedNames(providers);
final boolean isFullIndex = IndexDatabaseHelper.isFullIndex(mContext, localeStr,
final boolean isFullIndex = isFullIndex(mContext, localeStr,
fingerprint, providerVersionedNames);
if (isFullIndex) {
rebuildDatabase();
}
for (final ResolveInfo info : providers) {
if (!DatabaseIndexingUtils.isWellKnownProvider(info, mContext)) {
continue;
}
final String authority = info.providerInfo.authority;
final String packageName = info.providerInfo.packageName;
PreIndexData indexData = getIndexDataFromProviders(providers, isFullIndex);
if (isFullIndex) {
addIndexablesFromRemoteProvider(packageName, authority);
}
final long nonIndexableStartTime = System.currentTimeMillis();
addNonIndexablesKeysFromRemoteProvider(packageName, authority);
if (SettingsSearchIndexablesProvider.DEBUG) {
final long nonIndextableTime = System.currentTimeMillis() - nonIndexableStartTime;
Log.d(LOG_TAG, "performIndexing update non-indexable for package " + packageName
+ " took time: " + nonIndextableTime);
}
}
final long updateDatabaseStartTime = System.currentTimeMillis();
updateDatabase(isFullIndex, localeStr);
updateDatabase(indexData, isFullIndex, localeStr);
if (SettingsSearchIndexablesProvider.DEBUG) {
final long updateDatabaseTime = System.currentTimeMillis() - updateDatabaseStartTime;
Log.d(LOG_TAG, "performIndexing updateDatabase took time: " + updateDatabaseTime);
@@ -221,10 +171,37 @@ public class DatabaseIndexingManager {
}
}
@VisibleForTesting
PreIndexData getIndexDataFromProviders(List<ResolveInfo> providers, boolean isFullIndex) {
if (mCollector == null) {
mCollector = new IndexableDataCollector(mContext);
}
return mCollector.collectIndexableData(providers, isFullIndex);
}
/**
* Reconstruct the database in the following cases:
* - Language has changed
* - Build has changed
* Checks if the indexed data is obsolete, when either:
* - Device language has changed
* - Device has taken an OTA.
* In both cases, the device requires a full index.
*
* @param locale is the default for the device
* @param fingerprint id for the current build.
* @return true if a full index should be preformed.
*/
@VisibleForTesting
boolean isFullIndex(Context context, String locale, String fingerprint,
String providerVersionedNames) {
final boolean isLocaleIndexed = IndexDatabaseHelper.isLocaleAlreadyIndexed(context, locale);
final boolean isBuildIndexed = IndexDatabaseHelper.isBuildIndexed(context, fingerprint);
final boolean areProvidersIndexed = IndexDatabaseHelper
.areProvidersIndexed(context, providerVersionedNames);
return !(isLocaleIndexed && isBuildIndexed && areProvidersIndexed);
}
/**
* Drop the currently stored database, and clear the flags which mark the database as indexed.
*/
private void rebuildDatabase() {
// Drop the database when the locale or build has changed. This eliminates rows which are
@@ -244,16 +221,9 @@ public class DatabaseIndexingManager {
* @param localeStr the default locale for the device.
*/
@VisibleForTesting
void updateDatabase(boolean needsReindexing, String localeStr) {
final UpdateData copy;
synchronized (mDataToProcess) {
copy = mDataToProcess.copy();
mDataToProcess.clear();
}
final List<SearchIndexableData> dataToUpdate = copy.dataToUpdate;
final Map<String, Set<String>> nonIndexableKeys = copy.nonIndexableKeys;
void updateDatabase(PreIndexData indexData, boolean needsReindexing, String localeStr) {
final List<SearchIndexableData> dataToUpdate = indexData.dataToUpdate;
final Map<String, Set<String>> nonIndexableKeys = indexData.nonIndexableKeys;
final SQLiteDatabase database = getWritableDatabase();
if (database == null) {
@@ -378,99 +348,10 @@ public class DatabaseIndexingManager {
disabledResults.close();
}
@VisibleForTesting
boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
try {
final Context context = mBaseAuthority.equals(authority) ?
mContext : mContext.createPackageContext(packageName, 0);
final Uri uriForResources = buildUriForXmlResources(authority);
addIndexablesForXmlResourceUri(context, packageName, uriForResources,
SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS);
final Uri uriForRawData = buildUriForRawData(authority);
addIndexablesForRawDataUri(context, packageName, uriForRawData,
SearchIndexablesContract.INDEXABLES_RAW_COLUMNS);
return true;
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return false;
}
}
@VisibleForTesting
void addNonIndexablesKeysFromRemoteProvider(String packageName,
String authority) {
final List<String> keys =
getNonIndexablesKeysFromRemoteProvider(packageName, authority);
addNonIndexableKeys(packageName, keys);
}
private List<String> getNonIndexablesKeysFromRemoteProvider(String packageName,
String authority) {
try {
final Context packageContext = mContext.createPackageContext(packageName, 0);
final Uri uriForNonIndexableKeys = buildUriForNonIndexableKeys(authority);
return getNonIndexablesKeys(packageContext, uriForNonIndexableKeys,
SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS);
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return EMPTY_LIST;
}
}
private List<String> getNonIndexablesKeys(Context packageContext, Uri uri,
String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
if (cursor == null) {
Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString());
return EMPTY_LIST;
}
final List<String> result = new ArrayList<>();
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final String key = cursor.getString(COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE);
if (TextUtils.isEmpty(key) && Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
Log.v(LOG_TAG, "Empty non-indexable key from: "
+ packageContext.getPackageName());
continue;
}
result.add(key);
}
}
return result;
} finally {
cursor.close();
}
}
public void addIndexableData(SearchIndexableData data) {
synchronized (mDataToProcess) {
mDataToProcess.dataToUpdate.add(data);
}
}
public void addNonIndexableKeys(String authority, List<String> keys) {
synchronized (mDataToProcess) {
if (keys != null && !keys.isEmpty()) {
mDataToProcess.nonIndexableKeys.put(authority, new ArraySet<>(keys));
}
}
}
/**
* TODO (b/64951285): Deprecate this method
*
* Update the Index for a specific class name resources
*
* @param className the class name (typically a fragment name).
@@ -491,9 +372,9 @@ public class DatabaseIndexingManager {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
addIndexableData(res);
updateDatabase(false, Locale.getDefault().toString());
res.enabled = false;
// addIndexableData(res);
// updateDatabase(false, Locale.getDefault().toString());
// res.enabled = false;
}
});
}
@@ -507,126 +388,9 @@ public class DatabaseIndexingManager {
}
}
private static Uri buildUriForXmlResources(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
}
private static Uri buildUriForRawData(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.INDEXABLES_RAW_PATH);
}
private static Uri buildUriForNonIndexableKeys(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
}
private void addIndexablesForXmlResourceUri(Context packageContext, String packageName,
Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
if (cursor == null) {
Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString());
return;
}
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final int xmlResId = cursor.getInt(COLUMN_INDEX_XML_RES_RESID);
final String className = cursor.getString(COLUMN_INDEX_XML_RES_CLASS_NAME);
final int iconResId = cursor.getInt(COLUMN_INDEX_XML_RES_ICON_RESID);
final String action = cursor.getString(COLUMN_INDEX_XML_RES_INTENT_ACTION);
final String targetPackage = cursor.getString(
COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE);
final String targetClass = cursor.getString(
COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS);
SearchIndexableResource sir = new SearchIndexableResource(packageContext);
sir.xmlResId = xmlResId;
sir.className = className;
sir.packageName = packageName;
sir.iconResId = iconResId;
sir.intentAction = action;
sir.intentTargetPackage = targetPackage;
sir.intentTargetClass = targetClass;
addIndexableData(sir);
}
}
} finally {
cursor.close();
}
}
private void addIndexablesForRawDataUri(Context packageContext, String packageName,
Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
if (cursor == null) {
Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString());
return;
}
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final int providerRank = cursor.getInt(COLUMN_INDEX_RAW_RANK);
// TODO Remove rank
final String title = cursor.getString(COLUMN_INDEX_RAW_TITLE);
final String summaryOn = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_ON);
final String summaryOff = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_OFF);
final String entries = cursor.getString(COLUMN_INDEX_RAW_ENTRIES);
final String keywords = cursor.getString(COLUMN_INDEX_RAW_KEYWORDS);
final String screenTitle = cursor.getString(COLUMN_INDEX_RAW_SCREEN_TITLE);
final String className = cursor.getString(COLUMN_INDEX_RAW_CLASS_NAME);
final int iconResId = cursor.getInt(COLUMN_INDEX_RAW_ICON_RESID);
final String action = cursor.getString(COLUMN_INDEX_RAW_INTENT_ACTION);
final String targetPackage = cursor.getString(
COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE);
final String targetClass = cursor.getString(
COLUMN_INDEX_RAW_INTENT_TARGET_CLASS);
final String key = cursor.getString(COLUMN_INDEX_RAW_KEY);
final int userId = cursor.getInt(COLUMN_INDEX_RAW_USER_ID);
SearchIndexableRaw data = new SearchIndexableRaw(packageContext);
data.title = title;
data.summaryOn = summaryOn;
data.summaryOff = summaryOff;
data.entries = entries;
data.keywords = keywords;
data.screenTitle = screenTitle;
data.className = className;
data.packageName = packageName;
data.iconResId = iconResId;
data.intentAction = action;
data.intentTargetPackage = targetPackage;
data.intentTargetClass = targetClass;
data.key = key;
data.userId = userId;
addIndexableData(data);
}
}
} finally {
cursor.close();
}
}
public void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr,
@VisibleForTesting
void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr,
SearchIndexableData data, Map<String, Set<String>> nonIndexableKeys) {
if (data instanceof SearchIndexableResource) {
indexOneResource(database, localeStr, (SearchIndexableResource) data, nonIndexableKeys);
@@ -1010,38 +774,6 @@ public class DatabaseIndexingManager {
}
}
/**
* A private class to describe the indexDatabase data for the Index database
*/
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static class UpdateData {
public List<SearchIndexableData> dataToUpdate;
public List<SearchIndexableData> dataToDisable;
public Map<String, Set<String>> nonIndexableKeys;
public UpdateData() {
dataToUpdate = new ArrayList<>();
dataToDisable = new ArrayList<>();
nonIndexableKeys = new HashMap<>();
}
public UpdateData(UpdateData other) {
dataToUpdate = new ArrayList<>(other.dataToUpdate);
dataToDisable = new ArrayList<>(other.dataToDisable);
nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
}
public UpdateData copy() {
return new UpdateData(this);
}
public void clear() {
dataToUpdate.clear();
dataToDisable.clear();
nonIndexableKeys.clear();
}
}
public static class DatabaseRow {
public final String locale;
public final String updatedTitle;

View File

@@ -174,35 +174,6 @@ public class DatabaseIndexingUtils {
return null;
}
/**
* Only allow a "well known" SearchIndexablesProvider. The provider should:
*
* - have read/write {@link Manifest.permission#READ_SEARCH_INDEXABLES}
* - be from a privileged package
*/
static boolean isWellKnownProvider(ResolveInfo info, Context context) {
final String authority = info.providerInfo.authority;
final String packageName = info.providerInfo.applicationInfo.packageName;
if (TextUtils.isEmpty(authority) || TextUtils.isEmpty(packageName)) {
return false;
}
final String readPermission = info.providerInfo.readPermission;
final String writePermission = info.providerInfo.writePermission;
if (TextUtils.isEmpty(readPermission) || TextUtils.isEmpty(writePermission)) {
return false;
}
if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(readPermission) ||
!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(writePermission)) {
return false;
}
return isPrivilegedPackage(packageName, context);
}
static String normalizeHyphen(String input) {
return (input != null) ? input.replaceAll(NON_BREAKING_HYPHEN, HYPHEN) : EMPTY;
}
@@ -217,15 +188,4 @@ public class DatabaseIndexingUtils {
static String normalizeKeywords(String input) {
return (input != null) ? input.replaceAll(LIST_DELIMITERS, SPACE) : EMPTY;
}
private static boolean isPrivilegedPackage(String packageName, Context context) {
final PackageManager pm = context.getPackageManager();
try {
PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
return ((packInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}

View File

@@ -40,19 +40,19 @@ public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult
/* These indices are used to match the columns of the this loader's SELECT statement.
These are not necessarily the same order nor similar coverage as the schema defined in
IndexDatabaseHelper */
static final int COLUMN_INDEX_ID = 0;
static final int COLUMN_INDEX_TITLE = 1;
static final int COLUMN_INDEX_SUMMARY_ON = 2;
static final int COLUMN_INDEX_SUMMARY_OFF = 3;
static final int COLUMN_INDEX_CLASS_NAME = 4;
static final int COLUMN_INDEX_SCREEN_TITLE = 5;
static final int COLUMN_INDEX_ICON = 6;
static final int COLUMN_INDEX_INTENT_ACTION = 7;
static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9;
static final int COLUMN_INDEX_KEY = 10;
static final int COLUMN_INDEX_PAYLOAD_TYPE = 11;
static final int COLUMN_INDEX_PAYLOAD = 12;
public static final int COLUMN_INDEX_ID = 0;
public static final int COLUMN_INDEX_TITLE = 1;
public static final int COLUMN_INDEX_SUMMARY_ON = 2;
public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
public static final int COLUMN_INDEX_CLASS_NAME = 4;
public static final int COLUMN_INDEX_SCREEN_TITLE = 5;
public static final int COLUMN_INDEX_ICON = 6;
public static final int COLUMN_INDEX_INTENT_ACTION = 7;
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9;
public static final int COLUMN_INDEX_KEY = 10;
public static final int COLUMN_INDEX_PAYLOAD_TYPE = 11;
public static final int COLUMN_INDEX_PAYLOAD = 12;
public static final String[] SELECT_COLUMNS = {
IndexColumns.DOCID,

View File

@@ -35,7 +35,7 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "search_index.db";
private static final int DATABASE_VERSION = 117;
private static final String INDEX = "index";
private static final String SHARED_PREFS_TAG = "indexing_manager";
private static final String PREF_KEY_INDEXED_PROVIDERS = "indexed_providers";
@@ -179,7 +179,7 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
public IndexDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
mContext = context.getApplicationContext();
}
@Override
@@ -230,6 +230,10 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
}
public void reconstruct(SQLiteDatabase db) {
mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.edit()
.clear()
.commit();
dropTables(db);
bootstrapDB(db);
}
@@ -252,24 +256,6 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
return version;
}
/**
* Perform a full index on an OTA or when the locale has changed
*
* @param locale is the default for the device
* @param fingerprint id for the current build.
* @return true when the locale or build has changed since last index.
*/
@VisibleForTesting
static boolean isFullIndex(Context context, String locale, String fingerprint,
String providerVersionedNames) {
final boolean isLocaleIndexed = IndexDatabaseHelper.isLocaleAlreadyIndexed(context, locale);
final boolean isBuildIndexed = IndexDatabaseHelper.isBuildIndexed(context, fingerprint);
final boolean areProvidersIndexed = IndexDatabaseHelper
.areProvidersIndexed(context, providerVersionedNames);
return !(isLocaleIndexed && isBuildIndexed && areProvidersIndexed);
}
@VisibleForTesting
static String buildProviderVersionedNames(List<ResolveInfo> providers) {
StringBuilder sb = new StringBuilder();
@@ -282,44 +268,42 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
return sb.toString();
}
static void clearCachedIndexed(Context context) {
context.getSharedPreferences(INDEX, Context.MODE_PRIVATE).edit().clear().commit();
}
static void setLocaleIndexed(Context context, String locale) {
context.getSharedPreferences(INDEX, Context.MODE_PRIVATE)
context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.edit()
.putBoolean(locale, true)
.apply();
}
static void setProvidersIndexed(Context context, String providerVersionedNames) {
context.getSharedPreferences(INDEX, Context.MODE_PRIVATE)
context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.edit()
.putString(PREF_KEY_INDEXED_PROVIDERS, providerVersionedNames)
.apply();
}
static boolean isLocaleAlreadyIndexed(Context context, String locale) {
return context.getSharedPreferences(INDEX, Context.MODE_PRIVATE).getBoolean(locale, false);
return context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.getBoolean(locale, false);
}
static boolean areProvidersIndexed(Context context, String providerVersionedNames) {
final String indexedProviders = context.getSharedPreferences(INDEX, Context.MODE_PRIVATE)
.getString(PREF_KEY_INDEXED_PROVIDERS, null);
final String indexedProviders =
context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.getString(PREF_KEY_INDEXED_PROVIDERS, null);
return TextUtils.equals(indexedProviders, providerVersionedNames);
}
static boolean isBuildIndexed(Context context, String buildNo) {
return context.getSharedPreferences(INDEX, Context.MODE_PRIVATE).getBoolean(buildNo, false);
return context.getSharedPreferences(SHARED_PREFS_TAG,
Context.MODE_PRIVATE).getBoolean(buildNo, false);
}
static void setBuildIndexed(Context context, String buildNo) {
context.getSharedPreferences(INDEX, 0).edit().putBoolean(buildNo, true).commit();
context.getSharedPreferences(SHARED_PREFS_TAG, 0).edit().putBoolean(buildNo, true).commit();
}
private void dropTables(SQLiteDatabase db) {
clearCachedIndexed(mContext);
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_META_INDEX);
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_PREFS_INDEX);
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SAVED_QUERIES);

View File

@@ -74,8 +74,7 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
@Override
public DatabaseIndexingManager getIndexingManager(Context context) {
if (mDatabaseIndexingManager == null) {
mDatabaseIndexingManager = new DatabaseIndexingManager(context.getApplicationContext(),
context.getPackageName());
mDatabaseIndexingManager = new DatabaseIndexingManager(context.getApplicationContext());
}
return mDatabaseIndexingManager;
}

View File

@@ -44,6 +44,7 @@ import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.datausage.DataPlanUsageSummary;
import com.android.settings.datausage.DataUsageMeteredSettings;
import com.android.settings.datausage.DataUsageSummary;
import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
import com.android.settings.development.DevelopmentSettings;
import com.android.settings.deviceinfo.StorageDashboardFragment;
import com.android.settings.deviceinfo.StorageSettings;
@@ -213,6 +214,10 @@ public final class SearchIndexableResources {
R.drawable.ic_settings_notifications);
addIndex(DreamSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_display);
addIndex(SupportDashboardActivity.class, NO_DATA_RES_ID, R.drawable.ic_help);
addIndex(
AutomaticStorageManagerSettings.class,
NO_DATA_RES_ID,
R.drawable.ic_settings_storage);
}
private SearchIndexableResources() {

View File

@@ -0,0 +1,361 @@
/*
* Copyright (C) 2017 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.search.indexing;
import android.Manifest;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.provider.SearchIndexableResource;
import android.provider.SearchIndexablesContract;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.search.SettingsSearchIndexablesProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ENTRIES;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEY;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEYWORDS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SCREEN_TITLE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_OFF;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_TITLE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_USER_ID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
/**
* Collects all data from {@link android.provider.SearchIndexablesProvider} to be indexed.
*/
public class IndexableDataCollector {
private static final String TAG = "IndexableDataCollector";
// TODO (b/64938328) update to new search package.
private final String BASE_AUTHORITY = "com.android.settings";
private static final List<String> EMPTY_LIST = Collections.emptyList();
private Context mContext;
private PreIndexData mIndexData;
public IndexableDataCollector(Context context) {
mContext = context;
}
public PreIndexData collectIndexableData(List<ResolveInfo> providers, boolean isFullIndex) {
mIndexData = new PreIndexData();
for (final ResolveInfo info : providers) {
if (!isWellKnownProvider(info)) {
continue;
}
final String authority = info.providerInfo.authority;
final String packageName = info.providerInfo.packageName;
if (isFullIndex) {
addIndexablesFromRemoteProvider(packageName, authority);
}
final long nonIndexableStartTime = System.currentTimeMillis();
addNonIndexablesKeysFromRemoteProvider(packageName, authority);
if (SettingsSearchIndexablesProvider.DEBUG) {
final long nonIndexableTime = System.currentTimeMillis() - nonIndexableStartTime;
Log.d(TAG, "performIndexing update non-indexable for package " + packageName
+ " took time: " + nonIndexableTime);
}
}
return mIndexData;
}
private boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
try {
final Context context = BASE_AUTHORITY.equals(authority) ?
mContext : mContext.createPackageContext(packageName, 0);
final Uri uriForResources = buildUriForXmlResources(authority);
mIndexData.dataToUpdate.addAll(getIndexablesForXmlResourceUri(context, packageName,
uriForResources, SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS));
final Uri uriForRawData = buildUriForRawData(authority);
mIndexData.dataToUpdate.addAll(getIndexablesForRawDataUri(context, packageName,
uriForRawData, SearchIndexablesContract.INDEXABLES_RAW_COLUMNS));
return true;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return false;
}
}
@VisibleForTesting
List<SearchIndexableResource> getIndexablesForXmlResourceUri(Context packageContext,
String packageName, Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
List<SearchIndexableResource> resources = new ArrayList<>();
if (cursor == null) {
Log.w(TAG, "Cannot add index data for Uri: " + uri.toString());
return resources;
}
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final int xmlResId = cursor.getInt(COLUMN_INDEX_XML_RES_RESID);
final String className = cursor.getString(COLUMN_INDEX_XML_RES_CLASS_NAME);
final int iconResId = cursor.getInt(COLUMN_INDEX_XML_RES_ICON_RESID);
final String action = cursor.getString(COLUMN_INDEX_XML_RES_INTENT_ACTION);
final String targetPackage = cursor.getString(
COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE);
final String targetClass = cursor.getString(
COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS);
SearchIndexableResource sir = new SearchIndexableResource(packageContext);
sir.xmlResId = xmlResId;
sir.className = className;
sir.packageName = packageName;
sir.iconResId = iconResId;
sir.intentAction = action;
sir.intentTargetPackage = targetPackage;
sir.intentTargetClass = targetClass;
resources.add(sir);
}
}
} finally {
cursor.close();
}
return resources;
}
private void addNonIndexablesKeysFromRemoteProvider(String packageName,
String authority) {
final List<String> keys =
getNonIndexablesKeysFromRemoteProvider(packageName, authority);
if (keys != null && !keys.isEmpty()) {
mIndexData.nonIndexableKeys.put(authority, new ArraySet<>(keys));
}
}
@VisibleForTesting
List<String> getNonIndexablesKeysFromRemoteProvider(String packageName,
String authority) {
try {
final Context packageContext = mContext.createPackageContext(packageName, 0);
final Uri uriForNonIndexableKeys = buildUriForNonIndexableKeys(authority);
return getNonIndexablesKeys(packageContext, uriForNonIndexableKeys,
SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return EMPTY_LIST;
}
}
@VisibleForTesting
Uri buildUriForXmlResources(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
}
@VisibleForTesting
Uri buildUriForRawData(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.INDEXABLES_RAW_PATH);
}
@VisibleForTesting
Uri buildUriForNonIndexableKeys(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
}
@VisibleForTesting
List<SearchIndexableRaw> getIndexablesForRawDataUri(Context packageContext, String packageName,
Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
List<SearchIndexableRaw> rawData = new ArrayList<>();
if (cursor == null) {
Log.w(TAG, "Cannot add index data for Uri: " + uri.toString());
return rawData;
}
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final int providerRank = cursor.getInt(COLUMN_INDEX_RAW_RANK);
// TODO Remove rank
final String title = cursor.getString(COLUMN_INDEX_RAW_TITLE);
final String summaryOn = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_ON);
final String summaryOff = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_OFF);
final String entries = cursor.getString(COLUMN_INDEX_RAW_ENTRIES);
final String keywords = cursor.getString(COLUMN_INDEX_RAW_KEYWORDS);
final String screenTitle = cursor.getString(COLUMN_INDEX_RAW_SCREEN_TITLE);
final String className = cursor.getString(COLUMN_INDEX_RAW_CLASS_NAME);
final int iconResId = cursor.getInt(COLUMN_INDEX_RAW_ICON_RESID);
final String action = cursor.getString(COLUMN_INDEX_RAW_INTENT_ACTION);
final String targetPackage = cursor.getString(
COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE);
final String targetClass = cursor.getString(
COLUMN_INDEX_RAW_INTENT_TARGET_CLASS);
final String key = cursor.getString(COLUMN_INDEX_RAW_KEY);
final int userId = cursor.getInt(COLUMN_INDEX_RAW_USER_ID);
SearchIndexableRaw data = new SearchIndexableRaw(packageContext);
data.title = title;
data.summaryOn = summaryOn;
data.summaryOff = summaryOff;
data.entries = entries;
data.keywords = keywords;
data.screenTitle = screenTitle;
data.className = className;
data.packageName = packageName;
data.iconResId = iconResId;
data.intentAction = action;
data.intentTargetPackage = targetPackage;
data.intentTargetClass = targetClass;
data.key = key;
data.userId = userId;
rawData.add(data);
}
}
} finally {
cursor.close();
}
return rawData;
}
private List<String> getNonIndexablesKeys(Context packageContext, Uri uri,
String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
final List<String> result = new ArrayList<>();
if (cursor == null) {
Log.w(TAG, "Cannot add index data for Uri: " + uri.toString());
return result;
}
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final String key = cursor.getString(COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE);
if (TextUtils.isEmpty(key) && Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Empty non-indexable key from: "
+ packageContext.getPackageName());
continue;
}
result.add(key);
}
}
return result;
} finally {
cursor.close();
}
}
/**
* Only allow a "well known" SearchIndexablesProvider. The provider should:
*
* - have read/write {@link Manifest.permission#READ_SEARCH_INDEXABLES}
* - be from a privileged package
*/
@VisibleForTesting
boolean isWellKnownProvider(ResolveInfo info) {
final String authority = info.providerInfo.authority;
final String packageName = info.providerInfo.applicationInfo.packageName;
if (TextUtils.isEmpty(authority) || TextUtils.isEmpty(packageName)) {
return false;
}
final String readPermission = info.providerInfo.readPermission;
final String writePermission = info.providerInfo.writePermission;
if (TextUtils.isEmpty(readPermission) || TextUtils.isEmpty(writePermission)) {
return false;
}
if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(readPermission) ||
!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(writePermission)) {
return false;
}
return isPrivilegedPackage(packageName, mContext);
}
/**
* @return true if the {@param packageName} is privileged.
*/
private boolean isPrivilegedPackage(String packageName, Context context) {
final PackageManager pm = context.getPackageManager();
try {
PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
return ((packInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2017 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.search.indexing;
import android.provider.SearchIndexableData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Holds Data sources for indexable data.
* TODO (b/33577327) add getters and setters for data.
*/
public class PreIndexData {
public List<SearchIndexableData> dataToUpdate;
public Map<String, Set<String>> nonIndexableKeys;
public PreIndexData() {
dataToUpdate = new ArrayList<>();
nonIndexableKeys = new HashMap<>();
}
public PreIndexData(PreIndexData other) {
dataToUpdate = new ArrayList<>(other.dataToUpdate);
nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
}
public PreIndexData copy() {
return new PreIndexData(this);
}
public void clear() {
dataToUpdate.clear();
nonIndexableKeys.clear();
}
}

View File

@@ -78,7 +78,7 @@ public class ConfigureWifiSettings extends DashboardFragment {
final NetworkScoreManagerWrapper networkScoreManagerWrapper =
new NetworkScoreManagerWrapper(context.getSystemService(NetworkScoreManager.class));
mWifiWakeupPreferenceController = new WifiWakeupPreferenceController(
context, getLifecycle(), networkScoreManagerWrapper);
context, getLifecycle());
mUseOpenWifiPreferenceController = new UseOpenWifiPreferenceController(context, this,
networkScoreManagerWrapper, getLifecycle());
final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);

View File

@@ -38,6 +38,7 @@ import android.net.wifi.WpsInfo;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.PowerManager;
import android.os.Process;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
@@ -918,9 +919,8 @@ public class WifiSettings extends RestrictedSettingsFragment
getContentResolver(), Settings.Global.WIFI_WAKEUP_AVAILABLE, defaultWakeupAvailable)
== 1;
if (wifiWakeupAvailable) {
boolean wifiWakeupEnabled = Settings.Global.getInt(
getContentResolver(), Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1;
mConfigureWifiSettingsPreference.setSummary(getString(wifiWakeupEnabled
mConfigureWifiSettingsPreference.setSummary(getString(
isWifiWakeupEnabled()
? R.string.wifi_configure_settings_preference_summary_wakeup_on
: R.string.wifi_configure_settings_preference_summary_wakeup_off));
}
@@ -935,6 +935,20 @@ public class WifiSettings extends RestrictedSettingsFragment
}
}
private boolean isWifiWakeupEnabled() {
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
ContentResolver contentResolver = getContentResolver();
return Settings.Global.getInt(contentResolver,
Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1
&& Settings.Global.getInt(contentResolver,
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1
&& Settings.Global.getInt(contentResolver,
Settings.Global.AIRPLANE_MODE_ON, 0) == 0
&& Settings.Global.getInt(contentResolver,
Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1
&& !powerManager.isPowerSaveMode();
}
private void setOffMessage() {
final CharSequence title = getText(R.string.wifi_empty_list_wifi_off);
// Don't use WifiManager.isScanAlwaysAvailable() to check the Wi-Fi scanning mode. Instead,

View File

@@ -44,13 +44,10 @@ public class WifiWakeupPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause {
private static final String KEY_ENABLE_WIFI_WAKEUP = "enable_wifi_wakeup";
private final NetworkScoreManagerWrapper mNetworkScoreManager;
private SettingObserver mSettingObserver;
public WifiWakeupPreferenceController(
Context context, Lifecycle lifecycle, NetworkScoreManagerWrapper networkScoreManager) {
public WifiWakeupPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mNetworkScoreManager = networkScoreManager;
lifecycle.addObserver(this);
}
@@ -116,11 +113,9 @@ public class WifiWakeupPreferenceController extends AbstractPreferenceController
boolean networkRecommendationsEnabled = Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1;
boolean activeScorerSet = mNetworkScoreManager.getActiveScorerPackage() != null;
enableWifiWakeup.setEnabled(
networkRecommendationsEnabled && wifiScanningEnabled && activeScorerSet);
enableWifiWakeup.setEnabled(networkRecommendationsEnabled && wifiScanningEnabled);
if (!activeScorerSet) {
if (!networkRecommendationsEnabled) {
enableWifiWakeup.setSummary(R.string.wifi_wakeup_summary_scoring_disabled);
} else if (!wifiScanningEnabled) {
enableWifiWakeup.setSummary(R.string.wifi_wakeup_summary_scanning_disabled);

View File

@@ -64,7 +64,6 @@ com.android.settings.notification.AppNotificationSettings
com.android.settings.deviceinfo.PrivateVolumeSettings
com.android.settings.users.AppRestrictionsFragment
com.android.settings.deviceinfo.PrivateVolumeUnmount
com.android.settings.deletionhelper.AutomaticStorageManagerSettings
com.android.settings.notification.ZenAccessSettings
com.android.settings.accessibility.ToggleFontSizePreferenceFragment
com.android.settings.applications.PremiumSmsAccess

View File

@@ -32,9 +32,6 @@ public class OemLockManager {
return false;
}
public boolean canUserAllowOemUnlock() {
return true;
}
public boolean isOemUnlockAllowed() {
return false;
}

View File

@@ -42,6 +42,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -98,11 +99,29 @@ public class BluetoothDevicePreferenceTest {
when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(mCachedBluetoothDevice.startPairing()).thenReturn(true);
when(mCachedBluetoothDevice.hasHumanReadableName()).thenReturn(true);
mPreference.onClicked();
verify(mMetricsFeatureProvider).action(
mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
verify(mMetricsFeatureProvider, never()).action(mContext,
MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
}
@Test
public void onClicked_deviceNotBonded_shouldLogBluetoothPairEventAndPairWithoutNameEvent() {
when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(mCachedBluetoothDevice.startPairing()).thenReturn(true);
when(mCachedBluetoothDevice.hasHumanReadableName()).thenReturn(false);
mPreference.onClicked();
verify(mMetricsFeatureProvider).action(
mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
verify(mMetricsFeatureProvider).action(mContext,
MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
}
@Test

View File

@@ -19,6 +19,7 @@ package com.android.settings.dashboard;
import android.support.annotation.NonNull;
import android.support.v7.util.DiffUtil;
import android.support.v7.util.ListUpdateCallback;
import android.widget.RemoteViews;
import com.android.settings.TestConfig;
import com.android.settings.dashboard.conditional.AirplaneModeCondition;
@@ -35,6 +36,7 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -224,6 +226,28 @@ public class DashboardDataTest {
testDiffUtil(mDashboardDataWithOneConditions, mDashboardDataWithNoItems, testResultData);
}
@Test
public void testDiffUtil_typeSuggestedContainer_ResultDataNothingChanged() {
//Build testResultData
final List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
testResultData.add(new ListUpdateResult.ResultData(
ListUpdateResult.ResultData.TYPE_OPERATION_CHANGE, 0, 1));
Tile tile = new Tile();
tile.remoteViews = mock(RemoteViews.class);
DashboardData prevData = new DashboardData.Builder()
.setConditions(null)
.setCategory(null)
.setSuggestions(Arrays.asList(tile))
.build();
DashboardData currentData = new DashboardData.Builder()
.setConditions(null)
.setCategory(null)
.setSuggestions(Arrays.asList(tile))
.build();
testDiffUtil(prevData, currentData, testResultData);
}
/**
* Test when using the
* {@link com.android.settings.dashboard.DashboardData.ItemsDataDiffCallback}

View File

@@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceManager;
@@ -158,6 +159,7 @@ public class DashboardFragmentTest {
@Test
public void tintTileIcon_hasMetadata_shouldReturnIconTintableMetadata() {
final Tile tile = new Tile();
tile.icon = mock(Icon.class);
final Bundle metaData = new Bundle();
tile.metaData = metaData;
@@ -168,10 +170,19 @@ public class DashboardFragmentTest {
assertThat(mTestFragment.tintTileIcon(tile)).isTrue();
}
@Test
public void tintTileIcon_noIcon_shouldReturnFalse() {
final Tile tile = new Tile();
final Bundle metaData = new Bundle();
tile.metaData = metaData;
assertThat(mTestFragment.tintTileIcon(tile)).isFalse();
}
@Test
public void tintTileIcon_noMetadata_shouldReturnPackageNameCheck() {
final Tile tile = new Tile();
tile.icon = mock(Icon.class);
final Intent intent = new Intent();
tile.intent = intent;

View File

@@ -0,0 +1,83 @@
package com.android.settings.deletionhelper;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AutomaticStorageManagerDescriptionPreferenceControllerTest {
@Mock private PreferenceScreen mScreen;
@Mock private Preference mPreference;
private AutomaticStorageManagerDescriptionPreferenceController mController;
private Context mContext = RuntimeEnvironment.application;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mController = new AutomaticStorageManagerDescriptionPreferenceController(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
when(mPreference.getContext()).thenReturn(mContext);
}
@Test
public void displayPreference_asmDisabled_shouldHaveDescription() {
mController.displayPreference(mScreen);
verify(mPreference).setSummary(eq(R.string.automatic_storage_manager_text));
}
@Test
public void displayPreference_asmEnabledButUnused_shouldHaveDescription() {
Settings.Secure.putInt(
mContext.getContentResolver(),
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
1);
mController.displayPreference(mScreen);
verify(mPreference).setSummary(eq(R.string.automatic_storage_manager_text));
}
@Ignore("Robolectric doesn't do locale switching for date localization -- yet.")
@Test
@Config(qualifiers = "en")
public void displayPreference_asmEnabledAndUsed_shouldHaveDescriptionFilledOut() {
Settings.Secure.putInt(
mContext.getContentResolver(),
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
1);
Settings.Secure.putLong(
mContext.getContentResolver(),
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED,
10);
Settings.Secure.putLong(
mContext.getContentResolver(),
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
43200000); // January 1, 1970 12:00:00 PM to avoid timezone issues.
mController.displayPreference(mScreen);
verify(mPreference)
.setSummary(eq("10.00B total made available\n\nLast ran on January 1, 1970"));
}
}

View File

@@ -20,13 +20,18 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.os.storage.StorageManager;
import android.provider.SearchIndexableResource;
import android.util.SparseArray;
import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.drawer.CategoryKey;
import org.junit.Before;
@@ -68,6 +73,47 @@ public class StorageDashboardFragmentTest {
verify(activity).invalidateOptionsMenu();
}
@Test
public void test_cacheProviderProvidesValuesIfBothCached() {
CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class);
PrivateStorageInfo info = new PrivateStorageInfo(0, 0);
when(helper.getCachedPrivateStorageInfo()).thenReturn(info);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = new SparseArray<>();
when(helper.getCachedAppsStorageResult()).thenReturn(result);
mFragment.setCachedStorageValuesHelper(helper);
mFragment.initializeCachedValues();
assertThat(mFragment.getPrivateStorageInfo()).isEqualTo(info);
assertThat(mFragment.getAppsStorageResult()).isEqualTo(result);
}
@Test
public void test_cacheProviderDoesntProvideValuesIfAppsMissing() {
CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class);
PrivateStorageInfo info = new PrivateStorageInfo(0, 0);
when(helper.getCachedPrivateStorageInfo()).thenReturn(info);
mFragment.setCachedStorageValuesHelper(helper);
mFragment.initializeCachedValues();
assertThat(mFragment.getPrivateStorageInfo()).isNull();
assertThat(mFragment.getAppsStorageResult()).isNull();
}
@Test
public void test_cacheProviderDoesntProvideValuesIfVolumeInfoMissing() {
CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = new SparseArray<>();
when(helper.getCachedAppsStorageResult()).thenReturn(result);
mFragment.setCachedStorageValuesHelper(helper);
mFragment.initializeCachedValues();
assertThat(mFragment.getPrivateStorageInfo()).isNull();
assertThat(mFragment.getAppsStorageResult()).isNull();
}
@Test
public void testSearchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =

View File

@@ -0,0 +1,295 @@
/*
* Copyright (C) 2017 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.deviceinfo.storage;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.CACHE_APPS_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_APP_BYTES;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_AUDIO_BYTES;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_IMAGE_BYTES;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_TOTAL_BYTES;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_VIDEO_BYTES;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.FREE_BYTES_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.GAME_APPS_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.MUSIC_APPS_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.OTHER_APPS_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.PHOTO_APPS_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.SHARED_PREFERENCES_NAME;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TIMESTAMP_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TOTAL_BYTES_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.USER_ID_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.VIDEO_APPS_SIZE_KEY;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.SparseArray;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class CachedStorageValuesHelperTest {
private Context mContext;
@Mock private CachedStorageValuesHelper.Clock mMockClock;
private CachedStorageValuesHelper mCachedValuesHelper;
private SharedPreferences mSharedPreferences;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application.getApplicationContext();
mSharedPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 0);
mCachedValuesHelper = new CachedStorageValuesHelper(mContext, 0);
mCachedValuesHelper.mClock = mMockClock;
}
@Test
public void getCachedPrivateStorageInfo_cachedValuesAreLoaded() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(MUSIC_APPS_SIZE_KEY, 10)
.putLong(VIDEO_APPS_SIZE_KEY, 100)
.putLong(PHOTO_APPS_SIZE_KEY, 1000)
.putLong(OTHER_APPS_SIZE_KEY, 10000)
.putLong(CACHE_APPS_SIZE_KEY, 100000)
.putLong(EXTERNAL_TOTAL_BYTES, 2)
.putLong(EXTERNAL_AUDIO_BYTES, 22)
.putLong(EXTERNAL_VIDEO_BYTES, 222)
.putLong(EXTERNAL_IMAGE_BYTES, 2222)
.putLong(EXTERNAL_APP_BYTES, 22222)
.putLong(FREE_BYTES_KEY, 1000L)
.putLong(TOTAL_BYTES_KEY, 6000L)
.putInt(USER_ID_KEY, 0)
.putLong(TIMESTAMP_KEY, 10000L)
.apply();
PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info.freeBytes).isEqualTo(1000L);
assertThat(info.totalBytes).isEqualTo(6000L);
}
@Test
public void getCachedAppsStorageResult_cachedValuesAreLoaded() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 1)
.putLong(MUSIC_APPS_SIZE_KEY, 10)
.putLong(VIDEO_APPS_SIZE_KEY, 100)
.putLong(PHOTO_APPS_SIZE_KEY, 1000)
.putLong(OTHER_APPS_SIZE_KEY, 10000)
.putLong(CACHE_APPS_SIZE_KEY, 100000)
.putLong(EXTERNAL_TOTAL_BYTES, 222222)
.putLong(EXTERNAL_AUDIO_BYTES, 22)
.putLong(EXTERNAL_VIDEO_BYTES, 222)
.putLong(EXTERNAL_IMAGE_BYTES, 2222)
.putLong(EXTERNAL_APP_BYTES, 22222)
.putLong(FREE_BYTES_KEY, 1000L)
.putLong(TOTAL_BYTES_KEY, 5000L)
.putInt(USER_ID_KEY, 0)
.putLong(TIMESTAMP_KEY, 10000L)
.apply();
SparseArray<StorageAsyncLoader.AppsStorageResult> result =
mCachedValuesHelper.getCachedAppsStorageResult();
StorageAsyncLoader.AppsStorageResult primaryResult = result.get(0);
assertThat(primaryResult.gamesSize).isEqualTo(1L);
assertThat(primaryResult.musicAppsSize).isEqualTo(10L);
assertThat(primaryResult.videoAppsSize).isEqualTo(100L);
assertThat(primaryResult.photosAppsSize).isEqualTo(1000L);
assertThat(primaryResult.otherAppsSize).isEqualTo(10000L);
assertThat(primaryResult.cacheSize).isEqualTo(100000L);
assertThat(primaryResult.externalStats.totalBytes).isEqualTo(222222L);
assertThat(primaryResult.externalStats.audioBytes).isEqualTo(22L);
assertThat(primaryResult.externalStats.videoBytes).isEqualTo(222L);
assertThat(primaryResult.externalStats.imageBytes).isEqualTo(2222L);
assertThat(primaryResult.externalStats.appBytes).isEqualTo(22222L);
}
@Test
public void getCachedPrivateStorageInfo_nullIfDataIsStale() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10000000L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(MUSIC_APPS_SIZE_KEY, 10)
.putLong(VIDEO_APPS_SIZE_KEY, 100)
.putLong(PHOTO_APPS_SIZE_KEY, 1000)
.putLong(OTHER_APPS_SIZE_KEY, 10000)
.putLong(CACHE_APPS_SIZE_KEY, 100000)
.putLong(EXTERNAL_TOTAL_BYTES, 2)
.putLong(EXTERNAL_AUDIO_BYTES, 22)
.putLong(EXTERNAL_VIDEO_BYTES, 222)
.putLong(EXTERNAL_IMAGE_BYTES, 2222)
.putLong(EXTERNAL_APP_BYTES, 22222)
.putLong(FREE_BYTES_KEY, 1000L)
.putLong(TOTAL_BYTES_KEY, 5000L)
.putInt(USER_ID_KEY, 0)
.putLong(TIMESTAMP_KEY, 10000L)
.apply();
PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info).isNull();
}
@Test
public void getCachedAppsStorageResult_nullIfDataIsStale() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10000000L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(MUSIC_APPS_SIZE_KEY, 10)
.putLong(VIDEO_APPS_SIZE_KEY, 100)
.putLong(PHOTO_APPS_SIZE_KEY, 1000)
.putLong(OTHER_APPS_SIZE_KEY, 10000)
.putLong(CACHE_APPS_SIZE_KEY, 100000)
.putLong(EXTERNAL_TOTAL_BYTES, 2)
.putLong(EXTERNAL_AUDIO_BYTES, 22)
.putLong(EXTERNAL_VIDEO_BYTES, 222)
.putLong(EXTERNAL_IMAGE_BYTES, 2222)
.putLong(EXTERNAL_APP_BYTES, 22222)
.putLong(FREE_BYTES_KEY, 1000L)
.putLong(TOTAL_BYTES_KEY, 5000L)
.putInt(USER_ID_KEY, 0)
.putLong(TIMESTAMP_KEY, 10000L)
.apply();
SparseArray<StorageAsyncLoader.AppsStorageResult> result =
mCachedValuesHelper.getCachedAppsStorageResult();
assertThat(result).isNull();
}
@Test
public void getCachedPrivateStorageInfo_nullIfWrongUser() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(MUSIC_APPS_SIZE_KEY, 10)
.putLong(VIDEO_APPS_SIZE_KEY, 100)
.putLong(PHOTO_APPS_SIZE_KEY, 1000)
.putLong(OTHER_APPS_SIZE_KEY, 10000)
.putLong(CACHE_APPS_SIZE_KEY, 100000)
.putLong(EXTERNAL_TOTAL_BYTES, 2)
.putLong(EXTERNAL_AUDIO_BYTES, 22)
.putLong(EXTERNAL_VIDEO_BYTES, 222)
.putLong(EXTERNAL_IMAGE_BYTES, 2222)
.putLong(EXTERNAL_APP_BYTES, 22222)
.putLong(FREE_BYTES_KEY, 1000L)
.putLong(TOTAL_BYTES_KEY, 5000L)
.putInt(USER_ID_KEY, 1)
.putLong(TIMESTAMP_KEY, 10000L)
.apply();
PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info).isNull();
}
@Test
public void getCachedAppsStorageResult_nullIfWrongUser() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(MUSIC_APPS_SIZE_KEY, 10)
.putLong(VIDEO_APPS_SIZE_KEY, 100)
.putLong(PHOTO_APPS_SIZE_KEY, 1000)
.putLong(OTHER_APPS_SIZE_KEY, 10000)
.putLong(CACHE_APPS_SIZE_KEY, 100000)
.putLong(EXTERNAL_TOTAL_BYTES, 2)
.putLong(EXTERNAL_AUDIO_BYTES, 22)
.putLong(EXTERNAL_VIDEO_BYTES, 222)
.putLong(EXTERNAL_IMAGE_BYTES, 2222)
.putLong(EXTERNAL_APP_BYTES, 22222)
.putLong(FREE_BYTES_KEY, 1000L)
.putLong(TOTAL_BYTES_KEY, 5000L)
.putInt(USER_ID_KEY, 1)
.putLong(TIMESTAMP_KEY, 10000L)
.apply();
SparseArray<StorageAsyncLoader.AppsStorageResult> result =
mCachedValuesHelper.getCachedAppsStorageResult();
assertThat(result).isNull();
}
@Test
public void getCachedPrivateStorageInfo_nullIfEmpty() throws Exception {
PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info).isNull();
}
@Test
public void getCachedAppsStorageResult_nullIfEmpty() throws Exception {
SparseArray<StorageAsyncLoader.AppsStorageResult> result =
mCachedValuesHelper.getCachedAppsStorageResult();
assertThat(result).isNull();
}
@Test
public void cacheResult_succeeds() throws Exception {
when(mMockClock.getCurrentTime()).thenReturn(10000L);
final StorageStatsSource.ExternalStorageStats externalStats =
new StorageStatsSource.ExternalStorageStats(22222l, 2l, 20L, 200L, 2000L);
final StorageAsyncLoader.AppsStorageResult result =
new StorageAsyncLoader.AppsStorageResult();
result.gamesSize = 1L;
result.musicAppsSize = 10l;
result.videoAppsSize = 100L;
result.photosAppsSize = 1000L;
result.otherAppsSize = 10000L;
result.cacheSize = 100000l;
result.externalStats = externalStats;
final PrivateStorageInfo info = new PrivateStorageInfo(1000L, 6000L);
mCachedValuesHelper.cacheResult(info, result);
assertThat(mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1)).isEqualTo(1L);
assertThat(mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1)).isEqualTo(10L);
assertThat(mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1)).isEqualTo(100L);
assertThat(mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1)).isEqualTo(1000L);
assertThat(mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1)).isEqualTo(10000L);
assertThat(mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1)).isEqualTo(100000L);
assertThat(mSharedPreferences.getLong(EXTERNAL_TOTAL_BYTES, -1)).isEqualTo(22222L);
assertThat(mSharedPreferences.getLong(EXTERNAL_AUDIO_BYTES, -1)).isEqualTo(2L);
assertThat(mSharedPreferences.getLong(EXTERNAL_VIDEO_BYTES, -1)).isEqualTo(20L);
assertThat(mSharedPreferences.getLong(EXTERNAL_IMAGE_BYTES, -1)).isEqualTo(200L);
assertThat(mSharedPreferences.getLong(EXTERNAL_APP_BYTES, -1)).isEqualTo(2000L);
assertThat(mSharedPreferences.getLong(FREE_BYTES_KEY, -1)).isEqualTo(1000L);
assertThat(mSharedPreferences.getLong(TOTAL_BYTES_KEY, -1)).isEqualTo(6000L);
assertThat(mSharedPreferences.getInt(USER_ID_KEY, -1)).isEqualTo(0);
assertThat(mSharedPreferences.getLong(TIMESTAMP_KEY, -1)).isEqualTo(10000L);
};
}

View File

@@ -32,6 +32,7 @@ import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@@ -43,7 +44,7 @@ import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AssistGestureSettingsTest {
@Mock
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFakeFeatureFactory;
private AssistGestureSettings mSettings;
@@ -51,6 +52,7 @@ public class AssistGestureSettingsTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest(mContext);
mFakeFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mSettings = new AssistGestureSettings();
}

View File

@@ -17,24 +17,20 @@
package com.android.settings.search;
import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -43,19 +39,18 @@ import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.provider.SearchIndexableData;
import android.provider.SearchIndexableResource;
import android.util.ArrayMap;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.search.indexing.PreIndexData;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowDatabaseIndexingUtils;
import com.android.settings.testutils.shadow.ShadowRunnableAsyncTask;
import org.junit.After;
@@ -67,7 +62,6 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowContentResolver;
import java.util.ArrayList;
import java.util.Arrays;
@@ -84,8 +78,6 @@ import java.util.Set;
sdk = TestConfig.SDK_VERSION,
shadows = {
ShadowRunnableAsyncTask.class,
ShadowDatabaseIndexingUtils.class,
ShadowContentResolver.class
}
)
public class DatabaseIndexingManagerTest {
@@ -129,6 +121,8 @@ public class DatabaseIndexingManagerTest {
private DatabaseIndexingManager mManager;
private SQLiteDatabase mDb;
private final List<ResolveInfo> FAKE_PROVIDER_LIST = new ArrayList<>();
@Mock
private PackageManager mPackageManager;
@@ -136,10 +130,12 @@ public class DatabaseIndexingManagerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mManager = spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
mManager = spy(new DatabaseIndexingManager(mContext));
mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(FAKE_PROVIDER_LIST).when(mPackageManager)
.queryIntentContentProviders(any(Intent.class), anyInt());
FakeFeatureFactory.setupForTest(mContext);
}
@@ -755,113 +751,60 @@ public class DatabaseIndexingManagerTest {
@Test
public void testPerformIndexing_fullIndex_getsDataFromProviders() {
DummyProvider provider = new DummyProvider();
provider.onCreate();
ShadowContentResolver.registerProvider(AUTHORITY_ONE, provider);
SearchIndexableRaw rawData = getFakeRaw();
PreIndexData data = getPreIndexData(rawData);
doReturn(data).when(mManager).getIndexDataFromProviders(anyList(), anyBoolean());
doReturn(true).when(mManager).isFullIndex(any(Context.class), anyString(), anyString(),
anyString());
// Test that Indexables are added for Full indexing
when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
.thenReturn(getDummyResolveInfo());
mManager.performIndexing();
DatabaseIndexingManager manager =
spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
manager.performIndexing();
verify(manager).addIndexablesFromRemoteProvider(PACKAGE_ONE, AUTHORITY_ONE);
verify(manager).updateDatabase(true /* isFullIndex */, Locale.getDefault().toString());
verify(mManager).updateDatabase(data, true /* isFullIndex */,
Locale.getDefault().toString());
}
@Test
public void testPerformIndexing_incrementalIndex_noDataAdded() {
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
skipFullIndex(providerInfo);
DummyProvider provider = new DummyProvider();
provider.onCreate();
ShadowContentResolver.registerProvider(AUTHORITY_ONE, provider);
// Test that Indexables are added for Full indexing
when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
.thenReturn(providerInfo);
public void testPerformIndexing_fullIndex_databaseDropped() {
// Initialize the Manager and force rebuild
DatabaseIndexingManager manager =
spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
manager.mDataToProcess.dataToUpdate.clear();
manager.performIndexing();
verify(manager, times(0)).addDataToDatabase(any(SQLiteDatabase.class), anyString(),
anyList(), anyMap());
verify(manager, times(0)).addIndexablesFromRemoteProvider(PACKAGE_ONE, AUTHORITY_ONE);
verify(manager).updateDataInDatabase(any(SQLiteDatabase.class), anyMap());
}
@Test
public void testPerformIndexing_localeChanged_databaseDropped() {
DummyProvider provider = new DummyProvider();
provider.onCreate();
ShadowContentResolver.registerProvider(AUTHORITY_ONE, provider);
// Test that Indexables are added for Full indexing
when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
.thenReturn(getDummyResolveInfo());
// Initialize the Manager
DatabaseIndexingManager manager =
spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
spy(new DatabaseIndexingManager(mContext));
doReturn(false).when(mManager).isFullIndex(any(Context.class), anyString(), anyString(),
anyString());
// Insert data point which will be dropped
final String oldTitle = "This is French";
insertSpecialCase(oldTitle, true, "key");
// Add a data point to be added by the indexing
SearchIndexableRaw raw = new SearchIndexableRaw(mContext);
final String newTitle = "This is English";
raw.title = newTitle;
manager.mDataToProcess.dataToUpdate.add(raw);
insertSpecialCase("Ceci n'est pas un pipe", true, "oui oui mon ami");
manager.performIndexing();
// Assert that the New Title is inserted
final Cursor newCursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE data_title = '" +
newTitle + "'", null);
assertThat(newCursor.getCount()).isEqualTo(1);
// Assert that the Old Title is no longer in the database, since it was dropped
final Cursor oldCursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE data_title = '" +
oldTitle + "'", null);
final Cursor oldCursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
assertThat(oldCursor.getCount()).isEqualTo(0);
}
@Test
public void testPerformIndexing_onOta_FullIndex() {
DummyProvider provider = new DummyProvider();
provider.onCreate();
ShadowContentResolver.registerProvider(
AUTHORITY_ONE, provider
);
public void testPerformIndexing_isfullIndex() {
SearchIndexableRaw rawData = getFakeRaw();
PreIndexData data = getPreIndexData(rawData);
doReturn(data).when(mManager).getIndexDataFromProviders(anyList(), anyBoolean());
doReturn(true).when(mManager).isFullIndex(any(Context.class), anyString(), anyString(),
anyString());
// Test that Indexables are added for Full indexing
when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
.thenReturn(getDummyResolveInfo());
mManager.performIndexing();
DatabaseIndexingManager manager =
spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
manager.performIndexing();
verify(manager).updateDatabase(true /* isFullIndex */, Locale.getDefault().toString());
verify(mManager).updateDatabase(data, true /* isFullIndex */,
Locale.getDefault().toString());
}
@Test
public void testPerformIndexing_onPackageChange_shouldFullIndex() {
public void testPerformIndexing_onPackageChange_fullIndex() {
final List<ResolveInfo> providers = getDummyResolveInfo();
final String buildNumber = Build.FINGERPRINT;
final String locale = Locale.getDefault().toString();
skipFullIndex(providers);
// This snapshot is already indexed. Should return false
assertThat(IndexDatabaseHelper.isFullIndex(
assertThat(mManager.isFullIndex(
mContext, locale, buildNumber,
IndexDatabaseHelper.buildProviderVersionedNames(providers)))
.isFalse();
@@ -869,65 +812,46 @@ public class DatabaseIndexingManagerTest {
// Change provider version number, this should trigger full index.
providers.get(0).providerInfo.applicationInfo.versionCode++;
assertThat(IndexDatabaseHelper.isFullIndex(mContext, locale, buildNumber,
assertThat(mManager.isFullIndex(mContext, locale, buildNumber,
IndexDatabaseHelper.buildProviderVersionedNames(providers)))
.isTrue();
}
@Test
public void testPerformIndexing_onOta_buildNumberIsCached() {
DummyProvider provider = new DummyProvider();
provider.onCreate();
ShadowContentResolver.registerProvider(
AUTHORITY_ONE, provider
);
mManager.performIndexing();
// Test that Indexables are added for Full indexing
when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
.thenReturn(getDummyResolveInfo());
DatabaseIndexingManager manager =
spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
manager.performIndexing();
assertThat(IndexDatabaseHelper.getInstance(mContext).isBuildIndexed(mContext,
Build.FINGERPRINT)).isTrue();
assertThat(IndexDatabaseHelper.isBuildIndexed(mContext, Build.FINGERPRINT)).isTrue();
}
@Test
public void testFullUpdatedDatabase_noData_addDataToDatabaseNotCalled() {
mManager.updateDatabase(true /* isFullIndex */, localeStr);
mManager.mDataToProcess.dataToUpdate.clear();
PreIndexData emptydata = new PreIndexData();
mManager.updateDatabase(emptydata, true /* isFullIndex */, localeStr);
verify(mManager, times(0)).addDataToDatabase(any(SQLiteDatabase.class), anyString(),
anyList(), anyMap());
}
@Test
public void testFullUpdatedDatabase_updatedDataInDatabaseNotCalled() {
mManager.updateDatabase(true /* isFullIndex */, localeStr);
verify(mManager, times(0)).updateDataInDatabase(any(SQLiteDatabase.class), anyMap());
}
@Test
public void testLocaleUpdated_afterIndexing_localeNotAdded() {
mManager.updateDatabase(true /* isFullIndex */, localeStr);
assertThat(IndexDatabaseHelper.getInstance(mContext)
.isLocaleAlreadyIndexed(mContext, localeStr)).isFalse();
PreIndexData emptydata = new PreIndexData();
mManager.updateDatabase(emptydata, true /* isFullIndex */, localeStr);
assertThat(IndexDatabaseHelper.isLocaleAlreadyIndexed(mContext, localeStr)).isFalse();
}
@Test
public void testLocaleUpdated_afterFullIndexing_localeAdded() {
mManager.performIndexing();
assertThat(IndexDatabaseHelper.getInstance(mContext)
.isLocaleAlreadyIndexed(mContext, localeStr)).isTrue();
assertThat(IndexDatabaseHelper.isLocaleAlreadyIndexed(mContext, localeStr)).isTrue();
}
@Test
public void testUpdateDatabase_newEligibleData_addedToDatabase() {
// Test that addDataToDatabase is called when dataToUpdate is non-empty
mManager.mDataToProcess.dataToUpdate.add(getFakeRaw());
mManager.updateDatabase(true /* isFullIndex */, localeStr);
PreIndexData indexData = new PreIndexData();
indexData.dataToUpdate.add(getFakeRaw());
mManager.updateDatabase(indexData, true /* isFullIndex */, localeStr);
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
cursor.moveToPosition(0);
@@ -1020,8 +944,8 @@ public class DatabaseIndexingManagerTest {
@Test
public void testEmptyNonIndexableKeys_emptyDataKeyResources_addedToDatabase() {
insertSpecialCase(TITLE_ONE, true /* enabled */, null /* dataReferenceKey */);
mManager.updateDatabase(false, localeStr);
PreIndexData emptydata = new PreIndexData();
mManager.updateDatabase(emptydata, false /* needsReindexing */, localeStr);
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
cursor.moveToPosition(0);
@@ -1111,46 +1035,6 @@ public class DatabaseIndexingManagerTest {
return niks;
}
private List<ResolveInfo> getDummyResolveInfo() {
List<ResolveInfo> infoList = new ArrayList<>();
ResolveInfo info = new ResolveInfo();
info.providerInfo = new ProviderInfo();
info.providerInfo.exported = true;
info.providerInfo.authority = AUTHORITY_ONE;
info.providerInfo.packageName = PACKAGE_ONE;
info.providerInfo.applicationInfo = new ApplicationInfo();
infoList.add(info);
return infoList;
}
// TODO move this method and its counterpart in CursorToSearchResultConverterTest into
// a util class with public fields to assert values.
private Cursor getDummyCursor() {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
final String BLANK = "";
ArrayList<String> item =
new ArrayList<>(INDEXABLES_RAW_COLUMNS.length);
item.add("42"); // Rank
item.add(TITLE_ONE); // Title
item.add(BLANK); // Summary on
item.add(BLANK); // summary off
item.add(BLANK); // entries
item.add(BLANK); // keywords
item.add(BLANK); // screen title
item.add(BLANK); // classname
item.add("123"); // Icon
item.add(BLANK); // Intent action
item.add(BLANK); // target package
item.add(BLANK); // target class
item.add(KEY_ONE); // Key
item.add("-1"); // userId
cursor.addRow(item);
return cursor;
}
private void insertSpecialCase(String specialCase, boolean enabled, String key) {
ContentValues values = new ContentValues();
values.put(IndexDatabaseHelper.IndexColumns.DOCID, specialCase.hashCode());
@@ -1179,43 +1063,22 @@ public class DatabaseIndexingManagerTest {
mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
}
private class DummyProvider extends ContentProvider {
private PreIndexData getPreIndexData(SearchIndexableData fakeData) {
PreIndexData data = new PreIndexData();
data.dataToUpdate.add(fakeData);
return data;
}
@Override
public boolean onCreate() {
return false;
}
private List<ResolveInfo> getDummyResolveInfo() {
List<ResolveInfo> infoList = new ArrayList<>();
ResolveInfo info = new ResolveInfo();
info.providerInfo = new ProviderInfo();
info.providerInfo.exported = true;
info.providerInfo.authority = AUTHORITY_ONE;
info.providerInfo.packageName = PACKAGE_ONE;
info.providerInfo.applicationInfo = new ApplicationInfo();
infoList.add(info);
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
if (uri.toString().contains("xml")) {
return null;
}
return getDummyCursor();
}
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values,
@Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
return infoList;
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (C) 2017 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.search.indexing;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.provider.SearchIndexableResource;
import com.android.settings.TestConfig;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class IndexableDataCollectorTest {
private final String AUTHORITY_ONE = "authority";
private final String PACKAGE_ONE = "com.android.settings";
@Mock
ContentResolver mResolver;
Context mContext;
IndexableDataCollector mDataCollector;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(mResolver).when(mContext).getContentResolver();
//doReturn(mPackageManager).when(mContext).getPackageManager();
mDataCollector = spy(new IndexableDataCollector(mContext));
}
@Test
public void testCollectIndexableData_addsResourceData() {
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
doReturn(true).when(mDataCollector).isWellKnownProvider(any(ResolveInfo.class));
List<SearchIndexableResource> resources = getFakeResource();
doReturn(resources).when(mDataCollector).getIndexablesForXmlResourceUri(
any(Context.class), anyString(), any(Uri.class), any(String[].class));
PreIndexData data = mDataCollector.collectIndexableData(providerInfo,
true /* isFullIndex */);
assertThat(data.dataToUpdate).containsAllIn(resources);
}
@Test
public void testCollectIndexableData_addsRawData() {
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
doReturn(true).when(mDataCollector).isWellKnownProvider(any(ResolveInfo.class));
List<SearchIndexableRaw> rawData = getFakeRaw();
doReturn(rawData).when(mDataCollector).getIndexablesForRawDataUri(any(Context.class),
anyString(), any(Uri.class), any(String[].class));
PreIndexData data = mDataCollector.collectIndexableData(providerInfo,
true /* isFullIndex */);
assertThat(data.dataToUpdate).containsAllIn(rawData);
}
@Test
public void testCollectIndexableData_addsNonIndexables() {
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
doReturn(true).when(mDataCollector).isWellKnownProvider(any(ResolveInfo.class));
List<String> niks = getFakeNonIndexables();
doReturn(niks).when(mDataCollector).getNonIndexablesKeysFromRemoteProvider(anyString(),
anyString());
PreIndexData data = mDataCollector.collectIndexableData(providerInfo,
true /* isFullIndex */);
assertThat(data.nonIndexableKeys.get(AUTHORITY_ONE)).containsAllIn(niks);
}
private List<ResolveInfo> getDummyResolveInfo() {
List<ResolveInfo> infoList = new ArrayList<>();
ResolveInfo info = new ResolveInfo();
info.providerInfo = new ProviderInfo();
info.providerInfo.exported = true;
info.providerInfo.authority = AUTHORITY_ONE;
info.providerInfo.packageName = PACKAGE_ONE;
info.providerInfo.applicationInfo = new ApplicationInfo();
infoList.add(info);
return infoList;
}
private List<SearchIndexableResource> getFakeResource() {
List<SearchIndexableResource> resources = new ArrayList<>();
final String BLANK = "";
SearchIndexableResource sir = new SearchIndexableResource(mContext);
sir.rank = 0;
sir.xmlResId = 0;
sir.className = BLANK;
sir.packageName = BLANK;
sir.iconResId = 0;
sir.intentAction = BLANK;
sir.intentTargetPackage = BLANK;
sir.intentTargetClass = BLANK;
sir.enabled = true;
resources.add(sir);
return resources;
}
private List<SearchIndexableRaw> getFakeRaw() {
List<SearchIndexableRaw> rawData = new ArrayList<>();
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
data.title = "bront";
data.key = "brint";
rawData.add(data);
return rawData;
}
private List<String> getFakeNonIndexables() {
List<String> niks = new ArrayList<>();
niks.add("they're");
niks.add("good");
niks.add("dogs");
niks.add("brent");
return niks;
}
}

View File

@@ -56,8 +56,6 @@ public class WifiWakeupPreferenceControllerTest {
private static final String TEST_SCORER_PACKAGE_NAME = "Test Scorer";
private Context mContext;
@Mock
private NetworkScoreManagerWrapper mNetworkScorer;
private WifiWakeupPreferenceController mController;
@Before
@@ -65,11 +63,11 @@ public class WifiWakeupPreferenceControllerTest {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new WifiWakeupPreferenceController(
mContext, mock(Lifecycle.class), mNetworkScorer);
mContext, mock(Lifecycle.class));
Settings.System.putInt(mContext.getContentResolver(), WIFI_SCAN_ALWAYS_AVAILABLE, 1);
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 1);
SettingsShadowResources.overrideResource(
com.android.internal.R.integer.config_wifi_wakeup_available, 0);
when(mNetworkScorer.getActiveScorerPackage()).thenReturn(TEST_SCORER_PACKAGE_NAME);
}
@After
@@ -116,9 +114,8 @@ public class WifiWakeupPreferenceControllerTest {
}
@Test
public void updateState_preferenceSetCheckedAndSetEnabledWhenSettingsAreEnabled() {
public void updateState_preferenceSetCheckedAndSetEnabledWhenWakeupSettingEnabled() {
final SwitchPreference preference = mock(SwitchPreference.class);
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 1);
Settings.System.putInt(mContext.getContentResolver(), WIFI_WAKEUP_ENABLED, 1);
mController.updateState(preference);
@@ -129,22 +126,20 @@ public class WifiWakeupPreferenceControllerTest {
}
@Test
public void updateState_preferenceSetCheckedAndSetEnabledWhenSettingsAreDisabled() {
public void updateState_preferenceSetUncheckedAndSetEnabledWhenWakeupSettingDisabled() {
final SwitchPreference preference = mock(SwitchPreference.class);
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 0);
Settings.System.putInt(mContext.getContentResolver(), WIFI_WAKEUP_ENABLED, 0);
mController.updateState(preference);
verify(preference).setChecked(false);
verify(preference).setEnabled(false);
verify(preference).setEnabled(true);
verify(preference).setSummary(R.string.wifi_wakeup_summary);
}
@Test
public void updateState_preferenceSetUncheckedAndSetDisabledWhenWifiScanningDisabled() {
final SwitchPreference preference = mock(SwitchPreference.class);
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 1);
Settings.System.putInt(mContext.getContentResolver(), WIFI_WAKEUP_ENABLED, 1);
Settings.System.putInt(mContext.getContentResolver(), WIFI_SCAN_ALWAYS_AVAILABLE, 0);
@@ -158,9 +153,8 @@ public class WifiWakeupPreferenceControllerTest {
@Test
public void updateState_preferenceSetUncheckedAndSetDisabledWhenScoringDisabled() {
final SwitchPreference preference = mock(SwitchPreference.class);
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 1);
Settings.System.putInt(mContext.getContentResolver(), WIFI_WAKEUP_ENABLED, 1);
when(mNetworkScorer.getActiveScorerPackage()).thenReturn(null);
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 0);
mController.updateState(preference);