Implementing contact upgrade under low storage conditions.
Bug: 2498528
Change-Id: I2c85b0cbd4c7b804e61957695b803e22f995b405
diff --git a/res/layout-finger/contacts_list_content.xml b/res/layout-finger/contacts_list_content.xml
index 2474975..36c03ce 100644
--- a/res/layout-finger/contacts_list_content.xml
+++ b/res/layout-finger/contacts_list_content.xml
@@ -30,22 +30,6 @@
android:fastScrollEnabled="true"
/>
- <ScrollView android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true"
- >
- <TextView android:id="@+id/emptyText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/noContacts"
- android:textSize="20sp"
- android:textColor="?android:attr/textColorSecondary"
- android:paddingLeft="10dip"
- android:paddingRight="10dip"
- android:paddingTop="10dip"
- android:lineSpacingMultiplier="0.92"
- />
- </ScrollView>
+ <include layout="@layout/contacts_list_empty"/>
</LinearLayout>
diff --git a/res/layout-finger/contacts_list_empty.xml b/res/layout-finger/contacts_list_empty.xml
new file mode 100644
index 0000000..195da1e
--- /dev/null
+++ b/res/layout-finger/contacts_list_empty.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView android:id="@+id/emptyText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/noContacts"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
+ android:paddingTop="10dip"
+ android:lineSpacingMultiplier="0.92"
+ />
+
+ <LinearLayout android:id="@+id/import_failure"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="fill_horizontal"
+ android:padding="20dip"
+ android:visibility="gone">
+
+ <Button
+ android:id="@+id/import_failure_uninstall_apps"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/upgrade_out_of_memory_uninstall"/>
+
+ <Button
+ android:id="@+id/import_failure_retry_upgrade"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/upgrade_out_of_memory_retry"/>
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 38d63d0..39a2e18 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1114,4 +1114,18 @@
<!-- Text shown in the contacts app while the background process updates contacts after a locale change -->
<string name="locale_change_in_progress">Contact list is being updated to reflect the change of language.\n\nPlease wait...</string>
+
+ <!-- Text shown in the contacts app while the background process updates contacts after a system upgrade -->
+ <string name="upgrade_in_progress">Contact list is being updated.\n\nPlease wait...</string>
+
+ <!-- Text shown in the contacts app if the background process updating contacts fails because of memory shortage -->
+ <string name="upgrade_out_of_memory">Contacts are in the process of being upgraded.
+ \n\nThe upgrade process requires approximately <xliff:g id="size_in_megabytes">%d</xliff:g>Mb of
+ internal phone storage.\n\nChoose one of the following options:</string>
+
+ <!-- Button shown in the contacts app if the background process updating contacts fails because of memory shortage -->
+ <string name="upgrade_out_of_memory_uninstall">Uninstall some applications</string>
+
+ <!-- Button shown in the contacts app if the background process updating contacts fails because of memory shortage -->
+ <string name="upgrade_out_of_memory_retry">Retry upgrade</string>
</resources>
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 2dfab29..4a35287 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -100,6 +100,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.EditorInfo;
@@ -107,6 +108,7 @@
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.ListView;
@@ -440,7 +442,7 @@
private static final int QUERY_MODE_MAILTO = 1;
private static final int QUERY_MODE_TEL = 2;
- private boolean mProviderStatusNormal = true;
+ private int mProviderStatus = ProviderStatus.STATUS_NORMAL;
private boolean mSearchMode;
private boolean mShowNumberOfContacts;
@@ -1012,7 +1014,7 @@
mSearchEditText.requestFocus();
}
- if (!checkProviderState(mJustCreated)) {
+ if (!mSearchMode && !checkProviderState(mJustCreated)) {
return;
}
@@ -1032,6 +1034,13 @@
* @return true if the provider status is normal
*/
private boolean checkProviderState(boolean loadData) {
+ View importFailureView = findViewById(R.id.import_failure);
+ if (importFailureView == null) {
+ return true;
+ }
+
+ TextView messageView = (TextView) findViewById(R.id.emptyText);
+
// This query can be performed on the UI thread because
// the API explicitly allows such use.
Cursor cursor = getContentResolver().query(ProviderStatus.CONTENT_URI, new String[] {
@@ -1040,27 +1049,76 @@
try {
if (cursor.moveToFirst()) {
int status = cursor.getInt(0);
- switch (status) {
- case ProviderStatus.STATUS_NORMAL:
- mProviderStatusNormal = true;
- if (loadData) {
- startQuery();
- }
- return true;
+ if (status != mProviderStatus) {
+ mProviderStatus = status;
+ switch (status) {
+ case ProviderStatus.STATUS_NORMAL:
+ mAdapter.notifyDataSetInvalidated();
+ if (loadData) {
+ startQuery();
+ }
+ break;
- case ProviderStatus.STATUS_CHANGING_LOCALE:
- mProviderStatusNormal = false;
- TextView empty = (TextView) findViewById(R.id.emptyText);
- empty.setText(R.string.locale_change_in_progress);
- mAdapter.changeCursor(null);
- return false;
+ case ProviderStatus.STATUS_CHANGING_LOCALE:
+ messageView.setText(R.string.locale_change_in_progress);
+ mAdapter.changeCursor(null);
+ mAdapter.notifyDataSetInvalidated();
+ break;
+
+ case ProviderStatus.STATUS_UPGRADING:
+ messageView.setText(R.string.upgrade_in_progress);
+ mAdapter.changeCursor(null);
+ mAdapter.notifyDataSetInvalidated();
+ break;
+
+ case ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY:
+ long size = cursor.getLong(1);
+ String message = getResources().getString(
+ R.string.upgrade_out_of_memory, new Object[] {size});
+ messageView.setText(message);
+ configureImportFailureView(importFailureView);
+ mAdapter.changeCursor(null);
+ mAdapter.notifyDataSetInvalidated();
+ break;
+ }
}
}
} finally {
cursor.close();
}
- return true;
+ importFailureView.setVisibility(
+ mProviderStatus == ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY
+ ? View.VISIBLE
+ : View.GONE);
+ return mProviderStatus == ProviderStatus.STATUS_NORMAL;
+ }
+
+ private void configureImportFailureView(View importFailureView) {
+
+ OnClickListener listener = new OnClickListener(){
+
+ public void onClick(View v) {
+ switch(v.getId()) {
+ case R.id.import_failure_uninstall_apps: {
+ startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS));
+ break;
+ }
+ case R.id.import_failure_retry_upgrade: {
+ // Send a provider status update, which will trigger a retry
+ ContentValues values = new ContentValues();
+ values.put(ProviderStatus.STATUS, ProviderStatus.STATUS_UPGRADING);
+ getContentResolver().update(ProviderStatus.CONTENT_URI, values, null, null);
+ break;
+ }
+ }
+ }};
+
+ Button uninstallApps = (Button) findViewById(R.id.import_failure_uninstall_apps);
+ uninstallApps.setOnClickListener(listener);
+
+ Button retryUpgrade = (Button) findViewById(R.id.import_failure_retry_upgrade);
+ retryUpgrade.setOnClickListener(listener);
}
private String getTextFilter() {
@@ -1177,6 +1235,10 @@
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
boolean globalSearch) {
+ if (mProviderStatus != ProviderStatus.STATUS_NORMAL) {
+ return;
+ }
+
if (globalSearch) {
super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
} else {
@@ -1246,7 +1308,7 @@
}
@Override
- protected Dialog onCreateDialog(int id) {
+ protected Dialog onCreateDialog(int id, Bundle bundle) {
switch (id) {
case R.string.import_from_sim:
case R.string.import_from_sdcard: {
@@ -1310,7 +1372,7 @@
}).create();
}
}
- return super.onCreateDialog(id);
+ return super.onCreateDialog(id, bundle);
}
/**
@@ -1564,7 +1626,6 @@
return super.onContextItemSelected(item);
}
-
/**
* Event handler for the use case where the user starts typing without
* bringing up the search UI first.
@@ -2768,7 +2829,7 @@
@Override
public boolean isEmpty() {
- if (!mProviderStatusNormal) {
+ if (mProviderStatus != ProviderStatus.STATUS_NORMAL) {
return true;
}
@@ -3223,7 +3284,9 @@
@Override
public void changeCursor(Cursor cursor) {
- setLoading(false);
+ if (cursor != null) {
+ setLoading(false);
+ }
// Get the split between starred and frequent items, if the mode is strequent
mFrequentSeparatorPos = ListView.INVALID_POSITION;