Switch to recyclerview in ManageApplications
- Replace ListView with RecyclerView in layout - Replace ApplicationAdapter's superclass to be RecyclerView.Adapter - Change adapter interfaces (where necessary) to work with RecyclerView - Replace fast scroll with Recycler's mechanism (all in xml) - Removed section indexer (text bubble when fast scroll) because recyclerview doesn't support it. Bug: 64804294 Test: robotests Change-Id: I55b221836ce6abdeddf4568c8a8a5632cbddbd3b
This commit is contained in:
27
res/drawable/line.xml
Normal file
27
res/drawable/line.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
|
||||||
|
<padding
|
||||||
|
android:top="10dp"
|
||||||
|
android:left="10dp"
|
||||||
|
android:right="10dp"
|
||||||
|
android:bottom="10dp"/>
|
||||||
|
</shape>
|
25
res/drawable/line_drawable.xml
Normal file
25
res/drawable/line_drawable.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/line" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:drawable="@drawable/line" />
|
||||||
|
</selector>
|
32
res/drawable/thumb.xml
Normal file
32
res/drawable/thumb.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="8dp"
|
||||||
|
android:topRightRadius="8dp"
|
||||||
|
android:bottomLeftRadius="8dp"
|
||||||
|
android:bottomRightRadius="8dp"/>
|
||||||
|
|
||||||
|
<padding
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp" />
|
||||||
|
|
||||||
|
<solid android:color="?android:attr/colorControlNormal" />
|
||||||
|
|
||||||
|
</shape>
|
24
res/drawable/thumb_drawable.xml
Normal file
24
res/drawable/thumb_drawable.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/thumb"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:drawable="@drawable/thumb"/>
|
||||||
|
</selector>
|
@@ -14,7 +14,9 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
@@ -24,7 +26,8 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/list_container"
|
<LinearLayout
|
||||||
|
android:id="@+id/list_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
@@ -35,23 +38,29 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<FrameLayout android:layout_width="match_parent"
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0px"
|
android:layout_height="0px"
|
||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
|
||||||
<ListView android:id="@android:id/list"
|
<android.support.v7.widget.RecyclerView
|
||||||
android:drawSelectorOnTop="false"
|
android:id="@+id/apps_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
settings:fastScrollEnabled="true"
|
||||||
android:scrollbarStyle="@integer/preference_scrollbar_style" />
|
settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
|
settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
|
||||||
|
|
||||||
<TextView android:id="@android:id/empty"
|
<TextView
|
||||||
|
android:id="@android:id/empty"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/no_applications"
|
android:text="@string/no_applications"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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.applications.manageapplications;
|
||||||
|
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
|
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||||
|
|
||||||
|
public class ApplicationViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
private final TextView mAppName;
|
||||||
|
private final ImageView mAppIcon;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final TextView mSummary;
|
||||||
|
@VisibleForTesting
|
||||||
|
final TextView mDisabled;
|
||||||
|
|
||||||
|
ApplicationViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
mAppName = itemView.findViewById(android.R.id.title);
|
||||||
|
mAppIcon = itemView.findViewById(android.R.id.icon);
|
||||||
|
mSummary = itemView.findViewById(R.id.widget_text1);
|
||||||
|
mDisabled = itemView.findViewById(R.id.widget_text2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static View newView(LayoutInflater inflater, ViewGroup parent) {
|
||||||
|
final View root = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.preference_app, parent, false);
|
||||||
|
inflater.inflate(R.layout.widget_text_views,
|
||||||
|
root.findViewById(android.R.id.widget_frame));
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSummary(CharSequence summary) {
|
||||||
|
mSummary.setText(summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSummary(@StringRes int summary) {
|
||||||
|
mSummary.setText(summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEnabled(boolean isEnabled) {
|
||||||
|
itemView.setEnabled(isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTitle(CharSequence title) {
|
||||||
|
if (title == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mAppName.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIcon(Drawable icon) {
|
||||||
|
if (icon == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mAppIcon.setImageDrawable(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDisableView(ApplicationInfo info) {
|
||||||
|
if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
|
||||||
|
mDisabled.setVisibility(View.VISIBLE);
|
||||||
|
mDisabled.setText(R.string.not_installed);
|
||||||
|
} else if (!info.enabled || info.enabledSetting
|
||||||
|
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
|
||||||
|
mDisabled.setVisibility(View.VISIBLE);
|
||||||
|
mDisabled.setText(R.string.disabled);
|
||||||
|
} else {
|
||||||
|
mDisabled.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSizeText(AppEntry entry, CharSequence invalidSizeStr, int whichSize) {
|
||||||
|
if (ManageApplications.DEBUG) {
|
||||||
|
Log.d(ManageApplications.TAG, "updateSizeText of "
|
||||||
|
+ entry.label + " " + entry + ": " + entry.sizeStr);
|
||||||
|
}
|
||||||
|
if (entry.sizeStr != null) {
|
||||||
|
switch (whichSize) {
|
||||||
|
case ManageApplications.SIZE_INTERNAL:
|
||||||
|
setSummary(entry.internalSizeStr);
|
||||||
|
break;
|
||||||
|
case ManageApplications.SIZE_EXTERNAL:
|
||||||
|
setSummary(entry.externalSizeStr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setSummary(entry.sizeStr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (entry.size == ApplicationsState.SIZE_INVALID) {
|
||||||
|
setSummary(invalidSizeStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -35,12 +35,14 @@ public interface FileViewHolderController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the view within an AppViewHolder.
|
* Initializes the view within an AppViewHolder.
|
||||||
|
*
|
||||||
* @param holder The holder to use to initialize.
|
* @param holder The holder to use to initialize.
|
||||||
*/
|
*/
|
||||||
void setupView(AppViewHolder holder);
|
void setupView(ApplicationViewHolder holder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the behavior when the view is clicked.
|
* Handles the behavior when the view is clicked.
|
||||||
|
*
|
||||||
* @param fragment Fragment where the click originated.
|
* @param fragment Fragment where the click originated.
|
||||||
*/
|
*/
|
||||||
void onClick(Fragment fragment);
|
void onClick(Fragment fragment);
|
||||||
|
@@ -40,16 +40,14 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageItemInfo;
|
import android.content.pm.PackageItemInfo;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.icu.text.AlphabeticIndex;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.LocaleList;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.preference.PreferenceFrameLayout;
|
import android.preference.PreferenceFrameLayout;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -59,19 +57,11 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AbsListView;
|
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
|
||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.BaseAdapter;
|
|
||||||
import android.widget.Filter;
|
|
||||||
import android.widget.Filterable;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.SectionIndexer;
|
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
@@ -86,7 +76,6 @@ import com.android.settings.Settings.StorageUseActivity;
|
|||||||
import com.android.settings.Settings.UsageAccessSettingsActivity;
|
import com.android.settings.Settings.UsageAccessSettingsActivity;
|
||||||
import com.android.settings.Settings.WriteSettingsActivity;
|
import com.android.settings.Settings.WriteSettingsActivity;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.Utils;
|
|
||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
|
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
|
||||||
import com.android.settings.applications.AppStateBaseBridge;
|
import com.android.settings.applications.AppStateBaseBridge;
|
||||||
@@ -122,13 +111,13 @@ import com.android.settingslib.applications.ApplicationsState.AppFilter;
|
|||||||
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
|
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
|
||||||
import com.android.settingslib.applications.ApplicationsState.VolumeFilter;
|
import com.android.settingslib.applications.ApplicationsState.VolumeFilter;
|
||||||
import com.android.settingslib.applications.StorageStatsSource;
|
import com.android.settingslib.applications.StorageStatsSource;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.settingslib.wrapper.PackageManagerWrapper;
|
import com.android.settingslib.wrapper.PackageManagerWrapper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,7 +127,7 @@ import java.util.Set;
|
|||||||
* intent.
|
* intent.
|
||||||
*/
|
*/
|
||||||
public class ManageApplications extends InstrumentedPreferenceFragment
|
public class ManageApplications extends InstrumentedPreferenceFragment
|
||||||
implements OnItemClickListener, OnItemSelectedListener {
|
implements View.OnClickListener, OnItemSelectedListener {
|
||||||
|
|
||||||
static final String TAG = "ManageApplications";
|
static final String TAG = "ManageApplications";
|
||||||
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
@@ -185,23 +174,17 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
private ApplicationsState mApplicationsState;
|
private ApplicationsState mApplicationsState;
|
||||||
|
|
||||||
public int mListType;
|
public int mListType;
|
||||||
public AppFilterItem mFilter;
|
private AppFilterItem mFilter;
|
||||||
|
private ApplicationsAdapter mApplications;
|
||||||
public ApplicationsAdapter mApplications;
|
|
||||||
|
|
||||||
private View mLoadingContainer;
|
private View mLoadingContainer;
|
||||||
|
|
||||||
private View mListContainer;
|
private View mListContainer;
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
// ListView used to display list
|
|
||||||
private ListView mListView;
|
|
||||||
|
|
||||||
// Size resource used for packages whose size computation failed for some reason
|
// Size resource used for packages whose size computation failed for some reason
|
||||||
CharSequence mInvalidSizeStr;
|
CharSequence mInvalidSizeStr;
|
||||||
|
|
||||||
// layout inflater object used to inflate views
|
|
||||||
private LayoutInflater mInflater;
|
|
||||||
|
|
||||||
private String mCurrentPkgName;
|
private String mCurrentPkgName;
|
||||||
private int mCurrentUid;
|
private int mCurrentUid;
|
||||||
|
|
||||||
@@ -234,6 +217,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
private int mStorageType;
|
private int mStorageType;
|
||||||
private boolean mIsWorkOnly;
|
private boolean mIsWorkOnly;
|
||||||
private int mWorkUserId;
|
private int mWorkUserId;
|
||||||
|
private View mEmptyView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -304,25 +288,14 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
// initialize the inflater
|
|
||||||
mInflater = inflater;
|
|
||||||
|
|
||||||
mRootView = inflater.inflate(R.layout.manage_applications_apps, null);
|
mRootView = inflater.inflate(R.layout.manage_applications_apps, null);
|
||||||
mLoadingContainer = mRootView.findViewById(R.id.loading_container);
|
mLoadingContainer = mRootView.findViewById(R.id.loading_container);
|
||||||
mListContainer = mRootView.findViewById(R.id.list_container);
|
mListContainer = mRootView.findViewById(R.id.list_container);
|
||||||
if (mListContainer != null) {
|
if (mListContainer != null) {
|
||||||
// Create adapter and list view here
|
// Create adapter and list view here
|
||||||
View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
|
mEmptyView = mListContainer.findViewById(android.R.id.empty);
|
||||||
ListView lv = mListContainer.findViewById(android.R.id.list);
|
mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter,
|
||||||
if (emptyView != null) {
|
savedInstanceState);
|
||||||
lv.setEmptyView(emptyView);
|
|
||||||
}
|
|
||||||
lv.setOnItemClickListener(this);
|
|
||||||
lv.setSaveEnabled(true);
|
|
||||||
lv.setItemsCanFocus(true);
|
|
||||||
lv.setTextFilterEnabled(true);
|
|
||||||
mListView = lv;
|
|
||||||
mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mApplications.mHasReceivedLoadEntries =
|
mApplications.mHasReceivedLoadEntries =
|
||||||
savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false);
|
savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false);
|
||||||
@@ -347,11 +320,10 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
mVolumeUuid,
|
mVolumeUuid,
|
||||||
UserHandle.of(userId)));
|
UserHandle.of(userId)));
|
||||||
}
|
}
|
||||||
mListView.setAdapter(mApplications);
|
mRecyclerView = mListContainer.findViewById(R.id.apps_list);
|
||||||
mListView.setRecyclerListener(mApplications);
|
mRecyclerView.setLayoutManager(new LinearLayoutManager(
|
||||||
mListView.setFastScrollEnabled(isFastScrollEnabled());
|
getContext(), RecyclerView.VERTICAL, false /* reverseLayout */));
|
||||||
|
mRecyclerView.setAdapter(mApplications);
|
||||||
Utils.prepareCustomPreferencesList(container, mRootView, mListView, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to do this now because PreferenceFrameLayout looks at it
|
// We have to do this now because PreferenceFrameLayout looks at it
|
||||||
@@ -492,6 +464,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
|
outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
|
||||||
outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);
|
outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);
|
||||||
outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);
|
outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);
|
||||||
|
if (mApplications != null) {
|
||||||
|
mApplications.onSaveInstanceState(outState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -633,7 +608,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
case R.id.sort_order_alpha:
|
case R.id.sort_order_alpha:
|
||||||
case R.id.sort_order_size:
|
case R.id.sort_order_size:
|
||||||
mSortOrder = menuId;
|
mSortOrder = menuId;
|
||||||
mListView.setFastScrollEnabled(isFastScrollEnabled());
|
|
||||||
if (mApplications != null) {
|
if (mApplications != null) {
|
||||||
mApplications.rebuild(mSortOrder);
|
mApplications.rebuild(mSortOrder);
|
||||||
}
|
}
|
||||||
@@ -667,10 +641,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onClick(View view) {
|
||||||
if (mApplications == null) {
|
if (mApplications == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final int position = mRecyclerView.getChildAdapterPosition(view);
|
||||||
|
|
||||||
if (mApplications.getApplicationCount() > position) {
|
if (mApplications.getApplicationCount() > position) {
|
||||||
ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
|
ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
|
||||||
@@ -757,7 +732,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE);
|
mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
if (mFilterOptions.size() == 1) {
|
if (mFilterOptions.size() == 1) {
|
||||||
if (DEBUG) Log.d(TAG, "Auto selecting filter " + filter);
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Auto selecting filter " + filter);
|
||||||
|
}
|
||||||
mManageApplications.mFilterSpinner.setSelection(0);
|
mManageApplications.mFilterSpinner.setSelection(0);
|
||||||
mManageApplications.onItemSelected(null, null, 0, 0);
|
mManageApplications.onItemSelected(null, null, 0, 0);
|
||||||
}
|
}
|
||||||
@@ -777,7 +754,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
if (mManageApplications.mFilter == filter) {
|
if (mManageApplications.mFilter == filter) {
|
||||||
if (mFilterOptions.size() > 0) {
|
if (mFilterOptions.size() > 0) {
|
||||||
if (DEBUG) Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0));
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0));
|
||||||
|
}
|
||||||
mManageApplications.mFilterSpinner.setSelection(0);
|
mManageApplications.mFilterSpinner.setSelection(0);
|
||||||
mManageApplications.onItemSelected(null, null, 0, 0);
|
mManageApplications.onItemSelected(null, null, 0, 0);
|
||||||
}
|
}
|
||||||
@@ -795,38 +774,25 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static class ApplicationsAdapter extends RecyclerView.Adapter<ApplicationViewHolder>
|
||||||
* Custom adapter implementation for the ListView
|
implements ApplicationsState.Callbacks, AppStateBaseBridge.Callback {
|
||||||
* This adapter maintains a map for each displayed application and its properties
|
|
||||||
* An index value on each AppInfo object indicates the correct position or index
|
|
||||||
* in the list. If the list gets updated dynamically when the user is viewing the list of
|
|
||||||
* applications, we need to return the correct index of position. This is done by mapping
|
|
||||||
* the getId methods via the package name into the internal maps and indices.
|
|
||||||
* The order of applications in the list is mirrored in mAppLocalList
|
|
||||||
*/
|
|
||||||
static class ApplicationsAdapter extends BaseAdapter implements Filterable,
|
|
||||||
ApplicationsState.Callbacks, AppStateBaseBridge.Callback,
|
|
||||||
AbsListView.RecyclerListener, SectionIndexer {
|
|
||||||
|
|
||||||
private static final SectionInfo[] EMPTY_SECTIONS = new SectionInfo[0];
|
private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index";
|
||||||
|
private static final int VIEW_TYPE_APP = 0;
|
||||||
|
private static final int VIEW_TYPE_EXTRA_VIEW = 1;
|
||||||
|
|
||||||
private final ApplicationsState mState;
|
private final ApplicationsState mState;
|
||||||
private final ApplicationsState.Session mSession;
|
private final ApplicationsState.Session mSession;
|
||||||
private final ManageApplications mManageApplications;
|
private final ManageApplications mManageApplications;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final ArrayList<View> mActive = new ArrayList<>();
|
|
||||||
private final AppStateBaseBridge mExtraInfoBridge;
|
private final AppStateBaseBridge mExtraInfoBridge;
|
||||||
private final Handler mBgHandler;
|
|
||||||
private final Handler mFgHandler;
|
|
||||||
private final LoadingViewController mLoadingViewController;
|
private final LoadingViewController mLoadingViewController;
|
||||||
|
|
||||||
private AppFilterItem mAppFilter;
|
private AppFilterItem mAppFilter;
|
||||||
private ArrayList<ApplicationsState.AppEntry> mBaseEntries;
|
|
||||||
private ArrayList<ApplicationsState.AppEntry> mEntries;
|
private ArrayList<ApplicationsState.AppEntry> mEntries;
|
||||||
private boolean mResumed;
|
private boolean mResumed;
|
||||||
private int mLastSortMode = -1;
|
private int mLastSortMode = -1;
|
||||||
private int mWhichSize = SIZE_TOTAL;
|
private int mWhichSize = SIZE_TOTAL;
|
||||||
CharSequence mCurFilterPrefix;
|
|
||||||
private AppFilter mCompositeFilter;
|
private AppFilter mCompositeFilter;
|
||||||
private boolean mHasReceivedLoadEntries;
|
private boolean mHasReceivedLoadEntries;
|
||||||
private boolean mHasReceivedBridgeCallback;
|
private boolean mHasReceivedBridgeCallback;
|
||||||
@@ -836,39 +802,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
// fragment is paused. We need this special handling because app entries are added gradually
|
// fragment is paused. We need this special handling because app entries are added gradually
|
||||||
// when we rebuild the list after the user made some changes, like uninstalling an app.
|
// when we rebuild the list after the user made some changes, like uninstalling an app.
|
||||||
private int mLastIndex = -1;
|
private int mLastIndex = -1;
|
||||||
private int mLastTop;
|
|
||||||
|
|
||||||
private AlphabeticIndex.ImmutableIndex<Locale> mIndex;
|
|
||||||
private SectionInfo[] mSections = EMPTY_SECTIONS;
|
|
||||||
private int[] mPositionToSectionIndex;
|
|
||||||
|
|
||||||
private Filter mFilter = new Filter() {
|
|
||||||
@Override
|
|
||||||
protected FilterResults performFiltering(CharSequence constraint) {
|
|
||||||
ArrayList<ApplicationsState.AppEntry> entries
|
|
||||||
= applyPrefixFilter(constraint, mBaseEntries);
|
|
||||||
FilterResults fr = new FilterResults();
|
|
||||||
fr.values = entries;
|
|
||||||
fr.count = entries.size();
|
|
||||||
return fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
|
||||||
mCurFilterPrefix = constraint;
|
|
||||||
mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values;
|
|
||||||
rebuildSections();
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,
|
public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,
|
||||||
AppFilterItem appFilter) {
|
AppFilterItem appFilter, Bundle savedInstanceState) {
|
||||||
|
setHasStableIds(true);
|
||||||
mState = state;
|
mState = state;
|
||||||
mFgHandler = new Handler();
|
|
||||||
mBgHandler = new Handler(mState.getBackgroundLooper());
|
|
||||||
mSession = state.newSession(this);
|
mSession = state.newSession(this);
|
||||||
mManageApplications = manageApplications;
|
mManageApplications = manageApplications;
|
||||||
mLoadingViewController = new LoadingViewController(
|
mLoadingViewController = new LoadingViewController(
|
||||||
@@ -893,6 +831,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
} else {
|
} else {
|
||||||
mExtraInfoBridge = null;
|
mExtraInfoBridge = null;
|
||||||
}
|
}
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
mLastIndex = savedInstanceState.getInt(STATE_LAST_SCROLL_INDEX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCompositeFilter(AppFilter compositeFilter) {
|
public void setCompositeFilter(AppFilter compositeFilter) {
|
||||||
@@ -907,9 +848,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
|
|
||||||
public void setExtraViewController(FileViewHolderController extraViewController) {
|
public void setExtraViewController(FileViewHolderController extraViewController) {
|
||||||
mExtraViewController = extraViewController;
|
mExtraViewController = extraViewController;
|
||||||
mBgHandler.post(() -> {
|
// Start to query extra view's stats on background, and once done post result to main
|
||||||
|
// thread.
|
||||||
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
mExtraViewController.queryStats();
|
mExtraViewController.queryStats();
|
||||||
mFgHandler.post(() -> {
|
ThreadUtils.postOnMainThread(() -> {
|
||||||
onExtraViewCompleted();
|
onExtraViewCompleted();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -938,11 +881,13 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
mExtraInfoBridge.pause();
|
mExtraInfoBridge.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
// Record the current scroll position before pausing.
|
// Record the current scroll position before pausing.
|
||||||
mLastIndex = mManageApplications.mListView.getFirstVisiblePosition();
|
final LinearLayoutManager layoutManager =
|
||||||
View v = mManageApplications.mListView.getChildAt(0);
|
(LinearLayoutManager) mManageApplications.mRecyclerView.getLayoutManager();
|
||||||
mLastTop =
|
outState.putInt(STATE_LAST_SCROLL_INDEX, layoutManager.findFirstVisibleItemPosition());
|
||||||
(v == null) ? 0 : (v.getTop() - mManageApplications.mListView.getPaddingTop());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
@@ -960,6 +905,21 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
rebuild();
|
rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
final View view = ApplicationViewHolder.newView(
|
||||||
|
LayoutInflater.from(parent.getContext()), parent);
|
||||||
|
return new ApplicationViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
boolean isLastItem = (getItemCount() - 1) == position;
|
||||||
|
return hasExtraView() && isLastItem
|
||||||
|
? VIEW_TYPE_EXTRA_VIEW
|
||||||
|
: VIEW_TYPE_APP;
|
||||||
|
}
|
||||||
|
|
||||||
public void rebuild() {
|
public void rebuild() {
|
||||||
if (!mHasReceivedLoadEntries
|
if (!mHasReceivedLoadEntries
|
||||||
|| (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) {
|
|| (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) {
|
||||||
@@ -1008,11 +968,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
|
|
||||||
filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
|
filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
|
||||||
AppFilter finalFilterObj = filterObj;
|
AppFilter finalFilterObj = filterObj;
|
||||||
mBgHandler.post(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
|
final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
|
||||||
comparatorObj, false);
|
comparatorObj, false);
|
||||||
if (entries != null) {
|
if (entries != null) {
|
||||||
mFgHandler.post(() -> onRebuildComplete(entries));
|
ThreadUtils.postOnMainThread(() -> onRebuildComplete(entries));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1031,8 +991,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
ArrayList<ApplicationsState.AppEntry> entries) {
|
ArrayList<ApplicationsState.AppEntry> entries) {
|
||||||
int size = entries.size();
|
int size = entries.size();
|
||||||
// returnList will not have more entries than entries
|
// returnList will not have more entries than entries
|
||||||
ArrayList<ApplicationsState.AppEntry> returnEntries = new
|
ArrayList<ApplicationsState.AppEntry> returnEntries = new ArrayList<>(size);
|
||||||
ArrayList<ApplicationsState.AppEntry>(size);
|
|
||||||
|
|
||||||
// assume appinfo of same package but different users are grouped together
|
// assume appinfo of same package but different users are grouped together
|
||||||
PackageItemInfo lastInfo = null;
|
PackageItemInfo lastInfo = null;
|
||||||
@@ -1055,21 +1014,19 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
filterType == FILTER_APPS_POWER_WHITELIST_ALL) {
|
filterType == FILTER_APPS_POWER_WHITELIST_ALL) {
|
||||||
entries = removeDuplicateIgnoringUser(entries);
|
entries = removeDuplicateIgnoringUser(entries);
|
||||||
}
|
}
|
||||||
mBaseEntries = entries;
|
mEntries = entries;
|
||||||
if (mBaseEntries != null) {
|
|
||||||
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
|
|
||||||
rebuildSections();
|
|
||||||
} else {
|
|
||||||
mEntries = null;
|
|
||||||
mSections = EMPTY_SECTIONS;
|
|
||||||
mPositionToSectionIndex = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
|
if (getItemCount() == 0) {
|
||||||
|
mManageApplications.mRecyclerView.setVisibility(View.GONE);
|
||||||
|
mManageApplications.mEmptyView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
mManageApplications.mEmptyView.setVisibility(View.GONE);
|
||||||
|
mManageApplications.mRecyclerView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
// Restore the last scroll position if the number of entries added so far is bigger than
|
// Restore the last scroll position if the number of entries added so far is bigger than
|
||||||
// it.
|
// it.
|
||||||
if (mLastIndex != -1 && getCount() > mLastIndex) {
|
if (mLastIndex != -1 && getItemCount() > mLastIndex) {
|
||||||
mManageApplications.mListView.setSelectionFromTop(mLastIndex, mLastTop);
|
mManageApplications.mRecyclerView.getLayoutManager().scrollToPosition(mLastIndex);
|
||||||
mLastIndex = -1;
|
mLastIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,45 +1043,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
mManageApplications.setHasInstant(mState.haveInstantApps());
|
mManageApplications.setHasInstant(mState.haveInstantApps());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rebuildSections() {
|
|
||||||
if (mEntries != null && mManageApplications.mListView.isFastScrollEnabled()) {
|
|
||||||
// Rebuild sections
|
|
||||||
if (mIndex == null) {
|
|
||||||
LocaleList locales = mContext.getResources().getConfiguration().getLocales();
|
|
||||||
if (locales.size() == 0) {
|
|
||||||
locales = new LocaleList(Locale.ENGLISH);
|
|
||||||
}
|
|
||||||
AlphabeticIndex<Locale> index = new AlphabeticIndex(locales.get(0));
|
|
||||||
int localeCount = locales.size();
|
|
||||||
for (int i = 1; i < localeCount; i++) {
|
|
||||||
index.addLabels(locales.get(i));
|
|
||||||
}
|
|
||||||
// Ensure we always have some base English locale buckets
|
|
||||||
index.addLabels(Locale.ENGLISH);
|
|
||||||
mIndex = index.buildImmutableIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<SectionInfo> sections = new ArrayList<>();
|
|
||||||
int lastSecId = -1;
|
|
||||||
int totalEntries = mEntries.size();
|
|
||||||
mPositionToSectionIndex = new int[totalEntries];
|
|
||||||
|
|
||||||
for (int pos = 0; pos < totalEntries; pos++) {
|
|
||||||
String label = mEntries.get(pos).label;
|
|
||||||
int secId = mIndex.getBucketIndex(TextUtils.isEmpty(label) ? "" : label);
|
|
||||||
if (secId != lastSecId) {
|
|
||||||
lastSecId = secId;
|
|
||||||
sections.add(new SectionInfo(mIndex.getBucket(secId).getLabel(), pos));
|
|
||||||
}
|
|
||||||
mPositionToSectionIndex[pos] = sections.size() - 1;
|
|
||||||
}
|
|
||||||
mSections = sections.toArray(EMPTY_SECTIONS);
|
|
||||||
} else {
|
|
||||||
mSections = EMPTY_SECTIONS;
|
|
||||||
mPositionToSectionIndex = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void updateLoading() {
|
void updateLoading() {
|
||||||
final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0;
|
final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0;
|
||||||
@@ -1135,26 +1053,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix,
|
|
||||||
ArrayList<ApplicationsState.AppEntry> origEntries) {
|
|
||||||
if (prefix == null || prefix.length() == 0) {
|
|
||||||
return origEntries;
|
|
||||||
} else {
|
|
||||||
String prefixStr = ApplicationsState.normalize(prefix.toString());
|
|
||||||
final String spacePrefixStr = " " + prefixStr;
|
|
||||||
ArrayList<ApplicationsState.AppEntry> newEntries
|
|
||||||
= new ArrayList<ApplicationsState.AppEntry>();
|
|
||||||
for (int i = 0; i < origEntries.size(); i++) {
|
|
||||||
ApplicationsState.AppEntry entry = origEntries.get(i);
|
|
||||||
String nlabel = entry.getNormalizedLabel();
|
|
||||||
if (nlabel.startsWith(prefixStr) || nlabel.indexOf(spacePrefixStr) != -1) {
|
|
||||||
newEntries.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newEntries;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExtraInfoUpdated() {
|
public void onExtraInfoUpdated() {
|
||||||
mHasReceivedBridgeCallback = true;
|
mHasReceivedBridgeCallback = true;
|
||||||
@@ -1186,29 +1084,27 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageSizeChanged(String packageName) {
|
public void onPackageSizeChanged(String packageName) {
|
||||||
for (int i = 0; i < mActive.size(); i++) {
|
if (mEntries == null) {
|
||||||
AppViewHolder holder = (AppViewHolder) mActive.get(i).getTag();
|
return;
|
||||||
if (holder == null || holder.entry == null) {
|
}
|
||||||
|
final int size = mEntries.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final AppEntry entry = mEntries.get(i);
|
||||||
|
final ApplicationInfo info = entry.info;
|
||||||
|
if (info == null && !TextUtils.equals(packageName, info.packageName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ApplicationInfo info = holder.entry.info;
|
if (TextUtils.equals(mManageApplications.mCurrentPkgName, info.packageName)) {
|
||||||
if (info == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (holder.entry.info.packageName.equals(packageName)) {
|
|
||||||
synchronized (holder.entry) {
|
|
||||||
updateSummary(holder);
|
|
||||||
}
|
|
||||||
if (holder.entry.info.packageName.equals(mManageApplications.mCurrentPkgName)
|
|
||||||
&& mLastSortMode == R.id.sort_order_size) {
|
|
||||||
// We got the size information for the last app the
|
// We got the size information for the last app the
|
||||||
// user viewed, and are sorting by size... they may
|
// user viewed, and are sorting by size... they may
|
||||||
// have cleared data, so we immediately want to resort
|
// have cleared data, so we immediately want to resort
|
||||||
// the list with the new size to reflect it to the user.
|
// the list with the new size to reflect it to the user.
|
||||||
rebuild();
|
rebuild();
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
notifyItemChanged(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1227,46 +1123,30 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onExtraViewCompleted() {
|
public void onExtraViewCompleted() {
|
||||||
int size = mActive.size();
|
if (!hasExtraView()) {
|
||||||
// If we have no elements, don't do anything.
|
|
||||||
if (size < 1) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AppViewHolder holder = (AppViewHolder) mActive.get(size - 1).getTag();
|
// Update last item - this is assumed to be the extra view.
|
||||||
|
notifyItemChanged(getItemCount() - 1);
|
||||||
// HACK: The extra view has no AppEntry -- and should be the only element without one.
|
|
||||||
// Thus, if the last active element has no AppEntry, it is the extra view.
|
|
||||||
if (holder == null || holder.entry != null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mExtraViewController.setupView(holder);
|
@Override
|
||||||
}
|
public int getItemCount() {
|
||||||
|
|
||||||
public int getCount() {
|
|
||||||
if (mEntries == null) {
|
if (mEntries == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int extraViewAddition =
|
return mEntries.size() + (hasExtraView() ? 1 : 0);
|
||||||
(mExtraViewController != null && mExtraViewController.shouldShow()) ? 1 : 0;
|
|
||||||
return mEntries.size() + extraViewAddition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApplicationCount() {
|
public int getApplicationCount() {
|
||||||
return mEntries != null ? mEntries.size() : 0;
|
return mEntries != null ? mEntries.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getItem(int position) {
|
public AppEntry getAppEntry(int position) {
|
||||||
if (position == mEntries.size()) {
|
|
||||||
return mExtraViewController;
|
|
||||||
}
|
|
||||||
return mEntries.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationsState.AppEntry getAppEntry(int position) {
|
|
||||||
return mEntries.get(position);
|
return mEntries.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
if (position == mEntries.size()) {
|
if (position == mEntries.size()) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1274,142 +1154,76 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
return mEntries.get(position).id;
|
return mEntries.get(position).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areAllItemsEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled(int position) {
|
public boolean isEnabled(int position) {
|
||||||
if (position == mEntries.size() && mExtraViewController != null &&
|
if (getItemViewType(position) == VIEW_TYPE_EXTRA_VIEW
|
||||||
mExtraViewController.shouldShow()) {
|
|| mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
ApplicationsState.AppEntry entry = mEntries.get(position);
|
||||||
return !PowerWhitelistBackend.getInstance().isSysWhitelisted(entry.info.packageName);
|
return !PowerWhitelistBackend.getInstance().isSysWhitelisted(entry.info.packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
@Override
|
||||||
// A ViewHolder keeps references to children views to avoid unnecessary calls
|
public void onBindViewHolder(ApplicationViewHolder holder, int position) {
|
||||||
// to findViewById() on each row.
|
|
||||||
AppViewHolder holder = AppViewHolder.createOrRecycle(mManageApplications.mInflater,
|
|
||||||
convertView);
|
|
||||||
convertView = holder.rootView;
|
|
||||||
|
|
||||||
// Handle the extra view if it is the last entry.
|
|
||||||
if (mEntries != null && mExtraViewController != null && position == mEntries.size()) {
|
if (mEntries != null && mExtraViewController != null && position == mEntries.size()) {
|
||||||
|
// set up view for extra view controller
|
||||||
mExtraViewController.setupView(holder);
|
mExtraViewController.setupView(holder);
|
||||||
convertView.setEnabled(true);
|
|
||||||
} else {
|
} else {
|
||||||
// Bind the data efficiently with the holder
|
// Bind the data efficiently with the holder
|
||||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
ApplicationsState.AppEntry entry = mEntries.get(position);
|
||||||
synchronized (entry) {
|
synchronized (entry) {
|
||||||
holder.entry = entry;
|
holder.setTitle(entry.label);
|
||||||
if (entry.label != null) {
|
|
||||||
holder.appName.setText(entry.label);
|
|
||||||
}
|
|
||||||
mState.ensureIcon(entry);
|
mState.ensureIcon(entry);
|
||||||
if (entry.icon != null) {
|
holder.setIcon(entry.icon);
|
||||||
holder.appIcon.setImageDrawable(entry.icon);
|
updateSummary(holder, entry);
|
||||||
|
holder.updateDisableView(entry.info);
|
||||||
}
|
}
|
||||||
updateSummary(holder);
|
holder.setEnabled(isEnabled(position));
|
||||||
updateDisableView(holder.disabled, entry.info);
|
|
||||||
}
|
}
|
||||||
convertView.setEnabled(isEnabled(position));
|
holder.itemView.setOnClickListener(mManageApplications);
|
||||||
}
|
}
|
||||||
|
|
||||||
mActive.remove(convertView);
|
private void updateSummary(ApplicationViewHolder holder, AppEntry entry) {
|
||||||
mActive.add(convertView);
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void updateDisableView(TextView view, ApplicationInfo info) {
|
|
||||||
if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
view.setText(R.string.not_installed);
|
|
||||||
} else if (!info.enabled || info.enabledSetting
|
|
||||||
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
view.setText(R.string.disabled);
|
|
||||||
} else {
|
|
||||||
view.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSummary(AppViewHolder holder) {
|
|
||||||
switch (mManageApplications.mListType) {
|
switch (mManageApplications.mListType) {
|
||||||
case LIST_TYPE_NOTIFICATION:
|
case LIST_TYPE_NOTIFICATION:
|
||||||
if (holder.entry.extraInfo != null) {
|
if (entry.extraInfo != null) {
|
||||||
holder.summary.setText(InstalledAppDetails.getNotificationSummary(
|
holder.setSummary(InstalledAppDetails.getNotificationSummary(
|
||||||
(AppRow) holder.entry.extraInfo, mContext));
|
(AppRow) entry.extraInfo, mContext));
|
||||||
} else {
|
} else {
|
||||||
holder.summary.setText(null);
|
holder.setSummary(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_TYPE_USAGE_ACCESS:
|
case LIST_TYPE_USAGE_ACCESS:
|
||||||
if (holder.entry.extraInfo != null) {
|
if (entry.extraInfo != null) {
|
||||||
holder.summary.setText((new UsageState((PermissionState) holder.entry
|
holder.setSummary(
|
||||||
.extraInfo)).isPermissible()
|
(new UsageState((PermissionState) entry.extraInfo)).isPermissible()
|
||||||
? R.string.app_permission_summary_allowed
|
? R.string.app_permission_summary_allowed
|
||||||
: R.string.app_permission_summary_not_allowed);
|
: R.string.app_permission_summary_not_allowed);
|
||||||
} else {
|
} else {
|
||||||
holder.summary.setText(null);
|
holder.setSummary(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_TYPE_HIGH_POWER:
|
case LIST_TYPE_HIGH_POWER:
|
||||||
holder.summary.setText(HighPowerDetail.getSummary(mContext, holder.entry));
|
holder.setSummary(HighPowerDetail.getSummary(mContext, entry));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_TYPE_OVERLAY:
|
case LIST_TYPE_OVERLAY:
|
||||||
holder.summary.setText(DrawOverlayDetails.getSummary(mContext, holder.entry));
|
holder.setSummary(DrawOverlayDetails.getSummary(mContext, entry));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_TYPE_WRITE_SETTINGS:
|
case LIST_TYPE_WRITE_SETTINGS:
|
||||||
holder.summary.setText(WriteSettingsDetails.getSummary(mContext,
|
holder.setSummary(WriteSettingsDetails.getSummary(mContext, entry));
|
||||||
holder.entry));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_TYPE_MANAGE_SOURCES:
|
case LIST_TYPE_MANAGE_SOURCES:
|
||||||
holder.summary.setText(ExternalSourcesDetails.getPreferenceSummary(mContext,
|
holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));
|
||||||
holder.entry));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize);
|
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private boolean hasExtraView() {
|
||||||
public Filter getFilter() {
|
return mExtraViewController != null
|
||||||
return mFilter;
|
&& mExtraViewController.shouldShow();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMovedToScrapHeap(View view) {
|
|
||||||
mActive.remove(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] getSections() {
|
|
||||||
return mSections;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPositionForSection(int sectionIndex) {
|
|
||||||
return mSections[sectionIndex].position;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionForPosition(int position) {
|
|
||||||
return mPositionToSectionIndex[position];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1439,21 +1253,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SectionInfo {
|
|
||||||
final String label;
|
|
||||||
final int position;
|
|
||||||
|
|
||||||
public SectionInfo(String label, int position) {
|
|
||||||
this.label = label;
|
|
||||||
this.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
|
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
|
||||||
= new SummaryLoader.SummaryProviderFactory() {
|
= new SummaryLoader.SummaryProviderFactory() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -72,11 +72,11 @@ public class MusicViewHolderController implements FileViewHolderController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupView(AppViewHolder holder) {
|
public void setupView(ApplicationViewHolder holder) {
|
||||||
holder.appIcon.setImageDrawable(
|
holder.setIcon(
|
||||||
new InsetDrawable(mContext.getDrawable(R.drawable.ic_headset_24dp), INSET_SIZE));
|
new InsetDrawable(mContext.getDrawable(R.drawable.ic_headset_24dp), INSET_SIZE));
|
||||||
holder.appName.setText(mContext.getText(R.string.audio_files_title));
|
holder.setTitle(mContext.getText(R.string.audio_files_title));
|
||||||
holder.summary.setText(Formatter.formatFileSize(mContext, mMusicSize));
|
holder.setSummary(Formatter.formatFileSize(mContext, mMusicSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -71,11 +71,11 @@ public class PhotosViewHolderController implements FileViewHolderController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupView(AppViewHolder holder) {
|
public void setupView(ApplicationViewHolder holder) {
|
||||||
holder.appIcon.setImageDrawable(
|
holder.setIcon(
|
||||||
new InsetDrawable(mContext.getDrawable(R.drawable.ic_photo_library), INSET_SIZE));
|
new InsetDrawable(mContext.getDrawable(R.drawable.ic_photo_library), INSET_SIZE));
|
||||||
holder.appName.setText(mContext.getText(R.string.storage_detail_images));
|
holder.setTitle(mContext.getText(R.string.storage_detail_images));
|
||||||
holder.summary.setText(Formatter.formatFileSize(mContext, mFilesSize));
|
holder.setSummary(Formatter.formatFileSize(mContext, mFilesSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -32,7 +32,6 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.applications.manageapplications.AppViewHolder;
|
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@@ -14,9 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.applications.manageapplications;
|
package com.android.settings.development;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -57,24 +56,4 @@ public class AppViewHolder {
|
|||||||
return (AppViewHolder)convertView.getTag();
|
return (AppViewHolder)convertView.getTag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSizeText(CharSequence invalidSizeStr, int whichSize) {
|
|
||||||
if (ManageApplications.DEBUG) Log.i(ManageApplications.TAG, "updateSizeText of "
|
|
||||||
+ entry.label + " " + entry + ": " + entry.sizeStr);
|
|
||||||
if (entry.sizeStr != null) {
|
|
||||||
switch (whichSize) {
|
|
||||||
case ManageApplications.SIZE_INTERNAL:
|
|
||||||
summary.setText(entry.internalSizeStr);
|
|
||||||
break;
|
|
||||||
case ManageApplications.SIZE_EXTERNAL:
|
|
||||||
summary.setText(entry.externalSizeStr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
summary.setText(entry.sizeStr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (entry.size == ApplicationsState.SIZE_INVALID) {
|
|
||||||
summary.setText(invalidSizeStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.android.settings.display;
|
package com.android.settings.display;
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@@ -30,6 +28,8 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.GridView;
|
import android.widget.GridView;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.applications.manageapplications;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class ApplicationViewHolderTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private View mView;
|
||||||
|
private ApplicationViewHolder mHolder;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void seUp() {
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mView = ApplicationViewHolder.newView(LayoutInflater.from(mContext),
|
||||||
|
new FrameLayout(mContext));
|
||||||
|
mHolder = new ApplicationViewHolder(mView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateDisableView_appDisabledUntilUsed_shouldSetDisabled() {
|
||||||
|
final ApplicationInfo info = new ApplicationInfo();
|
||||||
|
info.flags = ApplicationInfo.FLAG_INSTALLED;
|
||||||
|
info.enabled = true;
|
||||||
|
info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
|
||||||
|
mHolder.updateDisableView(info);
|
||||||
|
|
||||||
|
assertThat(mHolder.mDisabled.getText()).isEqualTo(mContext.getText(R.string.disabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setSummaries() {
|
||||||
|
mHolder.setSummary("hello");
|
||||||
|
assertThat(mHolder.mSummary.getText()).isEqualTo("hello");
|
||||||
|
|
||||||
|
mHolder.setSummary(R.string.disabled);
|
||||||
|
assertThat(mHolder.mSummary.getText()).isEqualTo(mContext.getText(R.string.disabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateSize() {
|
||||||
|
final String invalidStr = "invalid";
|
||||||
|
final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
|
||||||
|
entry.internalSizeStr = "internal";
|
||||||
|
entry.externalSizeStr = "external";
|
||||||
|
entry.sizeStr = entry.internalSizeStr;
|
||||||
|
|
||||||
|
mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_INTERNAL);
|
||||||
|
assertThat(mHolder.mSummary.getText()).isEqualTo(entry.internalSizeStr);
|
||||||
|
|
||||||
|
mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_EXTERNAL);
|
||||||
|
assertThat(mHolder.mSummary.getText()).isEqualTo(entry.externalSizeStr);
|
||||||
|
|
||||||
|
entry.sizeStr = null;
|
||||||
|
entry.size = ApplicationsState.SIZE_INVALID;
|
||||||
|
mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_EXTERNAL);
|
||||||
|
assertThat(mHolder.mSummary.getText()).isEqualTo(invalidStr);
|
||||||
|
}
|
||||||
|
}
|
@@ -31,19 +31,16 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.os.Bundle;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.Settings;
|
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
@@ -102,30 +99,6 @@ public class ManageApplicationsTest {
|
|||||||
ReflectionHelpers.setField(mFragment, "mLifecycle", new Lifecycle());
|
ReflectionHelpers.setField(mFragment, "mLifecycle", new Lifecycle());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void launchFragment() {
|
|
||||||
SettingsRobolectricTestRunner.startSettingsFragment(
|
|
||||||
mFragment, Settings.ManageApplicationsActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateDisableView_appDisabledUntilUsed_shouldSetDisabled() {
|
|
||||||
final TextView view = mock(TextView.class);
|
|
||||||
final ApplicationInfo info = new ApplicationInfo();
|
|
||||||
info.flags = ApplicationInfo.FLAG_INSTALLED;
|
|
||||||
info.enabled = true;
|
|
||||||
info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
|
|
||||||
ManageApplications fragment = mock(ManageApplications.class);
|
|
||||||
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
|
||||||
final ManageApplications.ApplicationsAdapter adapter =
|
|
||||||
new ManageApplications.ApplicationsAdapter(mState, fragment,
|
|
||||||
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));
|
|
||||||
|
|
||||||
adapter.updateDisableView(view, info);
|
|
||||||
|
|
||||||
verify(view).setText(R.string.disabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateMenu_mainListType_showAppReset() {
|
public void updateMenu_mainListType_showAppReset() {
|
||||||
setUpOptionMenus();
|
setUpOptionMenus();
|
||||||
@@ -170,14 +143,12 @@ public class ManageApplicationsTest {
|
|||||||
ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
|
ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
|
||||||
ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
|
ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
|
||||||
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
||||||
final Handler handler = mock(Handler.class);
|
|
||||||
final ManageApplications.ApplicationsAdapter adapter =
|
final ManageApplications.ApplicationsAdapter adapter =
|
||||||
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
|
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
|
||||||
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
|
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
|
||||||
final LoadingViewController loadingViewController =
|
final LoadingViewController loadingViewController =
|
||||||
mock(LoadingViewController.class);
|
mock(LoadingViewController.class);
|
||||||
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
|
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
|
||||||
ReflectionHelpers.setField(adapter, "mFgHandler", handler);
|
|
||||||
|
|
||||||
// app loading completed
|
// app loading completed
|
||||||
ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true);
|
ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true);
|
||||||
@@ -196,15 +167,12 @@ public class ManageApplicationsTest {
|
|||||||
ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
|
ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
|
||||||
ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
|
ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
|
||||||
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
||||||
|
|
||||||
final Handler handler = mock(Handler.class);
|
|
||||||
final ManageApplications.ApplicationsAdapter adapter =
|
final ManageApplications.ApplicationsAdapter adapter =
|
||||||
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
|
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
|
||||||
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
|
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
|
||||||
final LoadingViewController loadingViewController =
|
final LoadingViewController loadingViewController =
|
||||||
mock(LoadingViewController.class);
|
mock(LoadingViewController.class);
|
||||||
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
|
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
|
||||||
ReflectionHelpers.setField(adapter, "mFgHandler", handler);
|
|
||||||
|
|
||||||
// app loading not yet completed
|
// app loading not yet completed
|
||||||
ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false);
|
ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false);
|
||||||
@@ -218,6 +186,10 @@ public class ManageApplicationsTest {
|
|||||||
public void onRebuildComplete_shouldHideLoadingView() {
|
public void onRebuildComplete_shouldHideLoadingView() {
|
||||||
final Context context = RuntimeEnvironment.application;
|
final Context context = RuntimeEnvironment.application;
|
||||||
final ManageApplications fragment = mock(ManageApplications.class);
|
final ManageApplications fragment = mock(ManageApplications.class);
|
||||||
|
final RecyclerView recyclerView = mock(RecyclerView.class);
|
||||||
|
final View emptyView = mock(View.class);
|
||||||
|
ReflectionHelpers.setField(fragment, "mRecyclerView", recyclerView);
|
||||||
|
ReflectionHelpers.setField(fragment, "mEmptyView", emptyView);
|
||||||
final View loadingContainer = mock(View.class);
|
final View loadingContainer = mock(View.class);
|
||||||
when(loadingContainer.getContext()).thenReturn(context);
|
when(loadingContainer.getContext()).thenReturn(context);
|
||||||
final View listContainer = mock(View.class);
|
final View listContainer = mock(View.class);
|
||||||
@@ -226,14 +198,12 @@ public class ManageApplicationsTest {
|
|||||||
ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer);
|
ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer);
|
||||||
ReflectionHelpers.setField(fragment, "mListContainer", listContainer);
|
ReflectionHelpers.setField(fragment, "mListContainer", listContainer);
|
||||||
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
when(fragment.getActivity()).thenReturn(mock(Activity.class));
|
||||||
final Handler handler = mock(Handler.class);
|
|
||||||
final ManageApplications.ApplicationsAdapter adapter =
|
final ManageApplications.ApplicationsAdapter adapter =
|
||||||
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
|
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
|
||||||
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
|
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
|
||||||
final LoadingViewController loadingViewController =
|
final LoadingViewController loadingViewController =
|
||||||
mock(LoadingViewController.class);
|
mock(LoadingViewController.class);
|
||||||
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
|
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
|
||||||
ReflectionHelpers.setField(adapter, "mFgHandler", handler);
|
|
||||||
ReflectionHelpers.setField(adapter, "mAppFilter",
|
ReflectionHelpers.setField(adapter, "mAppFilter",
|
||||||
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));
|
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));
|
||||||
|
|
||||||
|
@@ -28,11 +28,12 @@ import android.os.UserHandle;
|
|||||||
import android.os.storage.VolumeInfo;
|
import android.os.storage.VolumeInfo;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
import com.android.settingslib.applications.StorageStatsSource;
|
import com.android.settingslib.applications.StorageStatsSource;
|
||||||
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -51,14 +52,13 @@ public class MusicViewHolderControllerTest {
|
|||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
private Fragment mFragment;
|
private Fragment mFragment;
|
||||||
@Mock
|
@Mock
|
||||||
private StorageVolumeProvider mSvp;
|
|
||||||
@Mock
|
|
||||||
private StorageStatsSource mSource;
|
private StorageStatsSource mSource;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private MusicViewHolderController mController;
|
private MusicViewHolderController mController;
|
||||||
private VolumeInfo mVolume;
|
private VolumeInfo mVolume;
|
||||||
private AppViewHolder mHolder;
|
private View mView;
|
||||||
|
private ApplicationViewHolder mHolder;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -69,25 +69,26 @@ public class MusicViewHolderControllerTest {
|
|||||||
new UserHandle(0));
|
new UserHandle(0));
|
||||||
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
mHolder = AppViewHolder.createOrRecycle(inflater, null);
|
mView = ApplicationViewHolder.newView(inflater, new FrameLayout(mContext));
|
||||||
|
mHolder = new ApplicationViewHolder(mView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
|
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
|
||||||
mController.setupView(mHolder);
|
mController.setupView(mHolder);
|
||||||
|
|
||||||
assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00 B");
|
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("0.00 B");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void storageShouldRepresentStorageStatsQuery() throws Exception {
|
public void storageShouldRepresentStorageStatsQuery() throws Exception {
|
||||||
when(mSource.getExternalStorageStats(nullable(String.class), nullable(UserHandle.class))).thenReturn(
|
when(mSource.getExternalStorageStats(nullable(String.class), nullable(UserHandle.class)))
|
||||||
new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0, 0));
|
.thenReturn(new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0, 0));
|
||||||
|
|
||||||
mController.queryStats();
|
mController.queryStats();
|
||||||
mController.setupView(mHolder);
|
mController.setupView(mHolder);
|
||||||
|
|
||||||
assertThat(mHolder.summary.getText().toString()).isEqualTo("1.00 B");
|
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("1.00 B");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -27,11 +27,12 @@ import android.content.Intent;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.storage.VolumeInfo;
|
import android.os.storage.VolumeInfo;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
import com.android.settingslib.applications.StorageStatsSource;
|
import com.android.settingslib.applications.StorageStatsSource;
|
||||||
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -48,14 +49,14 @@ import org.robolectric.annotation.Config;
|
|||||||
public class PhotosViewHolderControllerTest {
|
public class PhotosViewHolderControllerTest {
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
private Fragment mFragment;
|
private Fragment mFragment;
|
||||||
|
|
||||||
@Mock private StorageVolumeProvider mSvp;
|
|
||||||
@Mock private StorageStatsSource mSource;
|
@Mock private StorageStatsSource mSource;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private PhotosViewHolderController mController;
|
private PhotosViewHolderController mController;
|
||||||
private VolumeInfo mVolume;
|
private VolumeInfo mVolume;
|
||||||
private AppViewHolder mHolder;
|
private View mView;
|
||||||
|
private ApplicationViewHolder mHolder;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -66,15 +67,16 @@ public class PhotosViewHolderControllerTest {
|
|||||||
new PhotosViewHolderController(
|
new PhotosViewHolderController(
|
||||||
mContext, mSource, mVolume.fsUuid, new UserHandle(0));
|
mContext, mSource, mVolume.fsUuid, new UserHandle(0));
|
||||||
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
mHolder = AppViewHolder.createOrRecycle(inflater, null);
|
mView = ApplicationViewHolder.newView(inflater, new FrameLayout(mContext));
|
||||||
|
mHolder = new ApplicationViewHolder(mView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
|
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
|
||||||
mController.setupView(mHolder);
|
mController.setupView(mHolder);
|
||||||
|
|
||||||
assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00 B");
|
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("0.00 B");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -85,7 +87,7 @@ public class PhotosViewHolderControllerTest {
|
|||||||
mController.queryStats();
|
mController.queryStats();
|
||||||
mController.setupView(mHolder);
|
mController.setupView(mHolder);
|
||||||
|
|
||||||
assertThat(mHolder.summary.getText().toString()).isEqualTo("11.00 B");
|
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("11.00 B");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user