Merge "Remove the work badge icon when a contact in search bar is a Google caller id" into ub-contactsdialer-b-dev
diff --git a/src/com/android/contacts/common/activity/AppCompatPreferenceActivity.java b/src/com/android/contacts/common/activity/AppCompatPreferenceActivity.java
new file mode 100644
index 0000000..c3b7e94
--- /dev/null
+++ b/src/com/android/contacts/common/activity/AppCompatPreferenceActivity.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 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.contacts.common.activity;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatDelegate;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
+ * to be used with AppCompat.
+ */
+public class AppCompatPreferenceActivity extends PreferenceActivity {
+ private AppCompatDelegate mDelegate;
+
+ private boolean mIsSafeToCommitTransactions;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ getDelegate().installViewFactory();
+ getDelegate().onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState);
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ getDelegate().onPostCreate(savedInstanceState);
+ }
+
+ public ActionBar getSupportActionBar() {
+ return getDelegate().getSupportActionBar();
+ }
+
+ public void setSupportActionBar(Toolbar toolbar) {
+ getDelegate().setSupportActionBar(toolbar);
+ }
+
+ @Override
+ public MenuInflater getMenuInflater() {
+ return getDelegate().getMenuInflater();
+ }
+
+ @Override
+ public void setContentView(int layoutResID) {
+ getDelegate().setContentView(layoutResID);
+ }
+
+ @Override
+ public void setContentView(View view) {
+ getDelegate().setContentView(view);
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ getDelegate().setContentView(view, params);
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ getDelegate().addContentView(view, params);
+ }
+
+ @Override
+ protected void onPostResume() {
+ super.onPostResume();
+ getDelegate().onPostResume();
+ }
+
+ @Override
+ protected void onTitleChanged(CharSequence title, int color) {
+ super.onTitleChanged(title, color);
+ getDelegate().setTitle(title);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ getDelegate().onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ getDelegate().onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ getDelegate().onDestroy();
+ }
+
+ @Override
+ public void invalidateOptionsMenu() {
+ getDelegate().invalidateOptionsMenu();
+ }
+
+ private AppCompatDelegate getDelegate() {
+ if (mDelegate == null) {
+ mDelegate = AppCompatDelegate.create(this, null);
+ }
+ return mDelegate;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mIsSafeToCommitTransactions = false;
+ }
+
+ /**
+ * Returns true if it is safe to commit {@link FragmentTransaction}s at this time, based on
+ * whether {@link Activity#onSaveInstanceState} has been called or not.
+ *
+ * Make sure that the current activity calls into
+ * {@link super.onSaveInstanceState(Bundle outState)} (if that method is overridden),
+ * so the flag is properly set.
+ */
+ public boolean isSafeToCommitTransactions() {
+ return mIsSafeToCommitTransactions;
+ }
+}
diff --git a/src/com/android/contacts/common/activity/LicenseActivity.java b/src/com/android/contacts/common/activity/LicenseActivity.java
index d72b305..9e86ee8 100644
--- a/src/com/android/contacts/common/activity/LicenseActivity.java
+++ b/src/com/android/contacts/common/activity/LicenseActivity.java
@@ -17,7 +17,8 @@
import com.android.contacts.common.R;
-import android.app.Activity;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.webkit.WebView;
@@ -25,7 +26,7 @@
/**
* Displays the licenses for all open source libraries.
*/
-public class LicenseActivity extends Activity {
+public class LicenseActivity extends AppCompatActivity {
private static final String LICENSE_FILE = "file:///android_asset/licenses.html";
private WebView mWebView;
@@ -35,6 +36,10 @@
setContentView(R.layout.licenses);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl(LICENSE_FILE);
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
+ }
}
@Override
diff --git a/src/com/android/contacts/common/compat/TelephonyManagerCompat.java b/src/com/android/contacts/common/compat/TelephonyManagerCompat.java
index 0f55c48..ec7907f 100644
--- a/src/com/android/contacts/common/compat/TelephonyManagerCompat.java
+++ b/src/com/android/contacts/common/compat/TelephonyManagerCompat.java
@@ -16,10 +16,13 @@
package com.android.contacts.common.compat;
-import android.content.Context;
+import android.net.Uri;
import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
+import com.android.contacts.common.ContactsUtils;
+
public class TelephonyManagerCompat {
public static final String TELEPHONY_MANAGER_CLASS = "android.telephony.TelephonyManager";
@@ -131,4 +134,40 @@
}
return false;
}
+
+ /**
+ * Returns the URI for the per-account voicemail ringtone set in Phone settings.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
+ * retrieve the voicemail ringtone.
+ * @return The URI for the ringtone to play when receiving a voicemail from a specific
+ * PhoneAccount.
+ */
+ @Nullable
+ public static Uri getVoicemailRingtoneUri(TelephonyManager telephonyManager,
+ PhoneAccountHandle accountHandle) {
+ if (!CompatUtils.isNCompatible()) {
+ return null;
+ }
+ return TelephonyManagerSdkCompat
+ .getVoicemailRingtoneUri(telephonyManager, accountHandle);
+ }
+
+ /**
+ * Returns whether vibration is set for voicemail notification in Phone settings.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
+ * retrieve the voicemail vibration setting.
+ * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
+ */
+ public static boolean isVoicemailVibrationEnabled(TelephonyManager telephonyManager,
+ PhoneAccountHandle accountHandle) {
+ if (!CompatUtils.isNCompatible()) {
+ return true;
+ }
+ return TelephonyManagerSdkCompat
+ .isVoicemailVibrationEnabled(telephonyManager, accountHandle);
+ }
}
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index d68788c..a2fb651 100644
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -23,11 +23,9 @@
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.SearchSnippets;
import android.text.TextUtils;
-import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.ContactsCompat;
@@ -72,7 +70,9 @@
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
- SearchSnippets.SNIPPET, // 8
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ SearchSnippets.SNIPPET, // 10
};
private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
@@ -84,7 +84,9 @@
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
- SearchSnippets.SNIPPET, // 8
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ SearchSnippets.SNIPPET, // 10
};
public static final int CONTACT_ID = 0;
@@ -95,7 +97,52 @@
public static final int CONTACT_PHOTO_URI = 5;
public static final int CONTACT_LOOKUP_KEY = 6;
public static final int CONTACT_IS_USER_PROFILE = 7;
- public static final int CONTACT_SNIPPET = 8;
+ public static final int CONTACT_TIMES_CONTACTED = 8;
+ public static final int CONTACT_STARRED = 9;
+ public static final int CONTACT_SNIPPET = 10;
+ }
+
+ protected static class StrequentQuery {
+
+ private static final String[] FILTER_PROJECTION_PRIMARY = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.IS_USER_PROFILE, // 7
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ // SearchSnippets.SNIPPET not supported
+ };
+
+ private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.IS_USER_PROFILE, // 7
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ // SearchSnippets.SNIPPET not supported
+ };
+
+ public static final int CONTACT_ID = 0;
+ public static final int CONTACT_DISPLAY_NAME = 1;
+ public static final int CONTACT_PRESENCE_STATUS = 2;
+ public static final int CONTACT_CONTACT_STATUS = 3;
+ public static final int CONTACT_PHOTO_ID = 4;
+ public static final int CONTACT_PHOTO_URI = 5;
+ public static final int CONTACT_LOOKUP_KEY = 6;
+ public static final int CONTACT_IS_USER_PROFILE = 7;
+ public static final int CONTACT_TIMES_CONTACTED = 8;
+ public static final int CONTACT_STARRED = 9;
+ // SearchSnippets.SNIPPET not supported
}
private CharSequence mUnknownNameText;
@@ -384,4 +431,11 @@
}
}
}
+
+ protected final String[] getStrequentProjection() {
+ final int sortOrder = getContactNameDisplayOrder();
+ return sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY
+ ? StrequentQuery.FILTER_PROJECTION_PRIMARY
+ : StrequentQuery.FILTER_PROJECTION_ALTERNATIVE;
+ }
}
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index 90b3d60..79fd12d 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -29,6 +29,7 @@
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.SearchSnippets;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.AppCompatCheckBox;
@@ -1481,7 +1482,8 @@
* Shows search snippet.
*/
public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
- if (cursor.getColumnCount() <= summarySnippetColumnIndex) {
+ if (cursor.getColumnCount() <= summarySnippetColumnIndex
+ || !SearchSnippets.SNIPPET.equals(cursor.getColumnName(summarySnippetColumnIndex))) {
setSnippet(null);
return;
}
diff --git a/src/com/android/contacts/common/list/DefaultContactListAdapter.java b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
index e50e9ce..ec91753 100644
--- a/src/com/android/contacts/common/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
@@ -44,6 +44,10 @@
public static final char SNIPPET_START_MATCH = '[';
public static final char SNIPPET_END_MATCH = ']';
+ // Whether to show strequent contacts before the normal type-to-filter search results.
+ // TODO(wjang): set this using phenotype
+ private final boolean mShowStrequentsSearchResultsFirst = false;
+
public DefaultContactListAdapter(Context context) {
super(context);
}
@@ -69,16 +73,26 @@
loader.setSelection("0");
} else {
final Builder builder = ContactsCompat.getContentUri().buildUpon();
- builder.appendPath(query); // Builder will encode the query
- builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
- String.valueOf(directoryId));
- if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE) {
- builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
- String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
- }
- builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1");
+ appendSearchParameters(builder, query, directoryId);
loader.setUri(builder.build());
loader.setProjection(getProjection(true));
+ if (mShowStrequentsSearchResultsFirst) {
+ // Filter out starred and frequently contacted contacts from the main loader
+ // query results
+ loader.setSelection(Contacts.TIMES_CONTACTED + "=0 AND "
+ + Contacts.STARRED + "=0");
+
+ // Strequent contacts will be merged back in before the main loader query
+ // results and after the profile (ME).
+ final ProfileAndContactsLoader profileAndContactsLoader =
+ (ProfileAndContactsLoader) loader;
+ profileAndContactsLoader.setLoadStrequent(true);
+ final Builder strequentBuilder =
+ Contacts.CONTENT_STREQUENT_FILTER_URI.buildUpon();
+ appendSearchParameters(strequentBuilder, query, directoryId);
+ profileAndContactsLoader.setStrequentUri(strequentBuilder.build());
+ profileAndContactsLoader.setStrequentProjection(getStrequentProjection());
+ }
}
} else {
configureUri(loader, directoryId, filter);
@@ -96,6 +110,17 @@
loader.setSortOrder(sortOrder);
}
+ private void appendSearchParameters(Builder builder, String query, long directoryId) {
+ builder.appendPath(query); // Builder will encode the query
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE) {
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
+ }
+ builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1");
+ }
+
protected void configureUri(CursorLoader loader, long directoryId, ContactListFilter filter) {
Uri uri = Contacts.CONTENT_URI;
if (filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
diff --git a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
index 698ef96..e68d4a1 100644
--- a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
+++ b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
@@ -20,7 +20,9 @@
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MergeCursor;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Profile;
import com.google.common.collect.Lists;
@@ -34,7 +36,10 @@
public class ProfileAndContactsLoader extends CursorLoader {
private boolean mLoadProfile;
+ private boolean mLoadStrequent;
private String[] mProjection;
+ private String[] mStrequentProjection;
+ private Uri mStrequentUri;
public ProfileAndContactsLoader(Context context) {
super(context);
@@ -44,11 +49,23 @@
mLoadProfile = flag;
}
+ public void setLoadStrequent(boolean flag) {
+ mLoadStrequent = flag;
+ }
+
public void setProjection(String[] projection) {
super.setProjection(projection);
mProjection = projection;
}
+ public void setStrequentProjection(String[] projection) {
+ mStrequentProjection = projection;
+ }
+
+ public void setStrequentUri(Uri uri) {
+ mStrequentUri = uri;
+ }
+
@Override
public Cursor loadInBackground() {
// First load the profile, if enabled.
@@ -56,6 +73,9 @@
if (mLoadProfile) {
cursors.add(loadProfile());
}
+ if (mLoadStrequent) {
+ cursors.add(loadStrequent());
+ }
// ContactsCursor.loadInBackground() can return null; MergeCursor
// correctly handles null cursors.
Cursor cursor = null;
@@ -101,4 +121,12 @@
cursor.close();
}
}
+
+ /**
+ * Loads starred and frequently contacted contacts
+ */
+ private Cursor loadStrequent() {
+ return getContext().getContentResolver().query(
+ mStrequentUri, mStrequentProjection, null, null, null);
+ }
}
diff --git a/src/com/android/contacts/common/logging/Logger.java b/src/com/android/contacts/common/logging/Logger.java
new file mode 100644
index 0000000..4e24caa
--- /dev/null
+++ b/src/com/android/contacts/common/logging/Logger.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 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.contacts.common.logging;
+
+import android.app.Activity;
+
+import com.android.contacts.commonbind.analytics.AnalyticsUtil;
+import com.android.contacts.commonbind.logging.ClearcutLoggerHelper;
+
+/**
+ * Logs analytics events.
+ */
+public abstract class Logger {
+ public static final String TAG = "Logger";
+
+ public static Logger getInstance() {
+ return ClearcutLoggerHelper.getInstance();
+ }
+
+ /**
+ * Logs an event indicating that a screen was displayed.
+ *
+ * @param screenType integer identifier of the displayed screen
+ * @param activity Parent activity of the displayed screen.
+ * @param tag Optional description of the displayed screen.
+ */
+ public static void logScreenView(int screenType, Activity activity, String tag) {
+ final Logger logger = getInstance();
+ if (logger != null) {
+ logger.logScreenViewImpl(screenType);
+ }
+ final String screenName = ScreenEvent.getScreenNameWithTag(
+ activity.getClass().getSimpleName(), tag);
+ AnalyticsUtil.sendScreenView(screenName, activity, tag);
+ }
+
+ public abstract void logScreenViewImpl(int screenType);
+ public abstract void logSearchEventImpl(SearchState searchState);
+}
diff --git a/src/com/android/contacts/common/logging/ScreenEvent.java b/src/com/android/contacts/common/logging/ScreenEvent.java
new file mode 100644
index 0000000..4d282d6
--- /dev/null
+++ b/src/com/android/contacts/common/logging/ScreenEvent.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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.contacts.common.logging;
+
+import android.text.TextUtils;
+
+/**
+ * Stores constants identifying individual screens/dialogs/fragments in the application, and also
+ * provides a mapping of integer id -> screen name mappings for analytics purposes.
+ */
+public final class ScreenEvent {
+ private static final String FRAGMENT_TAG_SEPARATOR = "#";
+
+ // Should match ContactsExtension.ScreenEvent.ScreenType values in
+ // http://cs/google3/logs/proto/wireless/android/contacts/contacts_extensions.proto
+ public static final int UNKNOWN = 0;
+ public static final int SEARCH = 1;
+ public static final int SEARCH_EXIT = 2;
+
+ public static final String TAG_SEARCH = "Search";
+ public static final String TAG_SEARCH_EXIT = "SearchExit";
+
+ /**
+ * Build a tagged version of the provided screenName if the tag is non-empty.
+ *
+ * @param screenName Name of the screen.
+ * @param tag Optional tag describing the screen.
+ * @return the unchanged screenName if the tag is {@code null} or empty, the tagged version of
+ * the screenName otherwise.
+ */
+ public static String getScreenNameWithTag(String screenName, String tag) {
+ if (TextUtils.isEmpty(tag)) {
+ return screenName;
+ }
+ return screenName + FRAGMENT_TAG_SEPARATOR + tag;
+ }
+}
diff --git a/src/com/android/contacts/common/logging/SearchState.java b/src/com/android/contacts/common/logging/SearchState.java
new file mode 100644
index 0000000..f4719e4
--- /dev/null
+++ b/src/com/android/contacts/common/logging/SearchState.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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.contacts.common.logging;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.common.base.Objects;
+
+/**
+ * Describes the results of a user search for a particular contact.
+ */
+public final class SearchState implements Parcelable {
+
+ /** The length of the query string input by the user. */
+ public int queryLength;
+
+ /** The number of partitions (groups of results) presented to the user. */
+ public int numPartitions;
+
+ /** The total number of results (across all partitions) presented to the user. */
+ public int numResults;
+
+ /** The number of results presented to the user in the partition that was selected. */
+ public int numResultsInSelectedPartition = -1;
+
+ /** The zero-based index of the partition in which the clicked query result resides. */
+ public int selectedPartition = -1;
+
+ /** The index of the clicked query result within its partition. */
+ public int selectedIndexInPartition = -1;
+
+ /**
+ * The zero-based index of the clicked query result among all results displayed to the user
+ * (across partitions).
+ */
+ public int selectedIndex = -1;
+
+ public static final Creator<SearchState> CREATOR = new Creator<SearchState>() {
+ @Override
+ public SearchState createFromParcel(Parcel in) {
+ return new SearchState(in);
+ }
+
+ @Override
+ public SearchState[] newArray(int size) {
+ return new SearchState[size];
+ }
+ };
+
+ public SearchState() {
+ }
+
+ protected SearchState(Parcel source) {
+ readFromParcel(source);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("queryLength", queryLength)
+ .add("numPartitions", numPartitions)
+ .add("numResults", numResults)
+ .add("numResultsInSelectedPartition", numResultsInSelectedPartition)
+ .add("selectedPartition", selectedPartition)
+ .add("selectedIndexInPartition", selectedIndexInPartition)
+ .add("selectedIndex", selectedIndex)
+ .toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(queryLength);
+ dest.writeInt(numPartitions);
+ dest.writeInt(numResults);
+ dest.writeInt(numResultsInSelectedPartition);
+ dest.writeInt(selectedPartition);
+ dest.writeInt(selectedIndexInPartition);
+ dest.writeInt(selectedIndex);
+ }
+
+ private void readFromParcel(Parcel source) {
+ queryLength = source.readInt();
+ numPartitions = source.readInt();
+ numResults = source.readInt();
+ numResultsInSelectedPartition = source.readInt();
+ selectedPartition = source.readInt();
+ selectedIndexInPartition = source.readInt();
+ selectedIndex = source.readInt();
+ }
+}
diff --git a/src/com/android/contacts/common/preference/AboutPreferenceFragment.java b/src/com/android/contacts/common/preference/AboutPreferenceFragment.java
new file mode 100644
index 0000000..3ab32d5
--- /dev/null
+++ b/src/com/android/contacts/common/preference/AboutPreferenceFragment.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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.contacts.common.preference;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.activity.LicenseActivity;
+
+/**
+ * This fragment shows the preferences for "about".
+ */
+public class AboutPreferenceFragment extends PreferenceFragment {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.preference_about);
+
+ // Set build version of Contacts App.
+ final PackageManager manager = getActivity().getPackageManager();
+ try {
+ final PackageInfo info = manager.getPackageInfo(getActivity().getPackageName(), 0);
+ final Preference versionPreference = findPreference(
+ getString(R.string.pref_build_version_key));
+ versionPreference.setSummary(info.versionName);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Nothing
+ }
+
+ final Preference licensePreference = findPreference(
+ getString(R.string.pref_open_source_licenses_key));
+ licensePreference.setIntent(new Intent(getActivity(), LicenseActivity.class));
+ }
+
+ @Override
+ public Context getContext() {
+ return getActivity();
+ }
+}
+
diff --git a/src/com/android/contacts/common/preference/ContactsPreferenceActivity.java b/src/com/android/contacts/common/preference/ContactsPreferenceActivity.java
new file mode 100644
index 0000000..3fd10d8
--- /dev/null
+++ b/src/com/android/contacts/common/preference/ContactsPreferenceActivity.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2009 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.contacts.common.preference;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.view.MenuItem;
+
+import com.android.contacts.common.activity.AppCompatPreferenceActivity;
+import com.android.contacts.common.R;
+
+/**
+ * Contacts settings.
+ */
+public final class ContactsPreferenceActivity extends AppCompatPreferenceActivity {
+
+ private static final String TAG_ABOUT_CONTACTS = "about_contacts";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
+ }
+
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new DisplayOptionsPreferenceFragment())
+ .commit();
+ setActivityTitle(R.string.activity_title_settings);
+ } else {
+ final AboutPreferenceFragment fragment = (AboutPreferenceFragment) getFragmentManager()
+ .findFragmentByTag(TAG_ABOUT_CONTACTS);
+ setActivityTitle(fragment == null ?
+ R.string.activity_title_settings : R.string.setting_about);
+ }
+ }
+
+ public void showAboutFragment() {
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new AboutPreferenceFragment(), TAG_ABOUT_CONTACTS)
+ .addToBackStack(null)
+ .commit();
+ setActivityTitle(R.string.setting_about);
+ }
+
+ /**
+ * Returns true if there are no preferences to display and therefore the
+ * corresponding menu item can be removed.
+ */
+ public static boolean isEmpty(Context context) {
+ return !context.getResources().getBoolean(R.bool.config_sort_order_user_changeable)
+ && !context.getResources().getBoolean(R.bool.config_display_order_user_changeable)
+ && !context.getResources().getBoolean(
+ R.bool.config_default_account_user_changeable);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (getFragmentManager().getBackStackEntryCount() > 0) {
+ setActivityTitle(R.string.activity_title_settings);
+ getFragmentManager().popBackStack();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ private void setActivityTitle(int res) {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setTitle(res);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/preference/ContactsPreferences.java b/src/com/android/contacts/common/preference/ContactsPreferences.java
index 37448e3..5815ef0 100644
--- a/src/com/android/contacts/common/preference/ContactsPreferences.java
+++ b/src/com/android/contacts/common/preference/ContactsPreferences.java
@@ -72,7 +72,7 @@
public static final boolean PREF_DISPLAY_ONLY_PHONES_DEFAULT = false;
- public static final String DO_NOT_SYNC_CONTACT_METADATA_MSG = "Do not sync contact metadata.";
+ public static final String DO_NOT_SYNC_CONTACT_METADATA_MSG = "Do not sync metadata";
public static final String CONTACT_METADATA_AUTHORITY = "com.android.contacts.metadata";
diff --git a/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java b/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
index 3a5c536..6f91616 100644
--- a/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
+++ b/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
@@ -17,24 +17,21 @@
package com.android.contacts.common.preference;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.os.Bundle;
-import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
import com.android.contacts.common.R;
-import com.android.contacts.common.activity.LicenseActivity;
+import com.android.contacts.common.compat.MetadataSyncEnabledCompat;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
import java.util.List;
/**
- * This fragment shows the preferences for the first header.
+ * This fragment shows the preferences for "display options"
*/
public class DisplayOptionsPreferenceFragment extends PreferenceFragment {
@@ -45,34 +42,51 @@
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preference_display_options);
- // Remove "Default account" setting if no writable accounts.
+ removeUnsupportedPreferences();
+
+ final Preference aboutPreference = findPreference("about");
+ aboutPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ ((ContactsPreferenceActivity) getActivity()).showAboutFragment();
+ return true;
+ }
+ });
+ }
+
+ private void removeUnsupportedPreferences() {
+ // Disable sort order for CJK locales where it is not supported
+ final Resources resources = getResources();
+ if (!resources.getBoolean(R.bool.config_sort_order_user_changeable)) {
+ getPreferenceScreen().removePreference(findPreference("sortOrder"));
+ }
+
+ // Disable display order for CJK locales as well
+ if (!resources.getBoolean(R.bool.config_display_order_user_changeable)) {
+ getPreferenceScreen().removePreference(findPreference("displayOrder"));
+ }
+
+ // Remove the "Default account" setting if there aren't any writable accounts
final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(getContext());
final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(
/* contactWritableOnly */ true);
if (accounts.isEmpty()) {
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
- preferenceScreen.removePreference((ListPreference) findPreference("accounts"));
+ getPreferenceScreen().removePreference(findPreference("accounts"));
}
- // STOPSHIP Show this option when 1) metadata sync is enabled and 2) at least one
- // focus google account.
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
- preferenceScreen.removePreference((ListPreference) findPreference("contactMetadata"));
-
- // Set build version of Contacts App.
- final PackageManager manager = getActivity().getPackageManager();
- try {
- final PackageInfo info = manager.getPackageInfo(getActivity().getPackageName(), 0);
- final Preference versionPreference = findPreference(
- getString(R.string.pref_build_version_key));
- versionPreference.setSummary(info.versionName);
- } catch (PackageManager.NameNotFoundException e) {
- // Nothing
+ // Show Contact metadata sync option when 1) metadata sync is enabled
+ // and 2) there is at least one focus google account
+ boolean hasFocusGoogleAccount = false;
+ for (AccountWithDataSet account : accounts) {
+ if (GoogleAccountType.ACCOUNT_TYPE.equals(account.type) && account.dataSet == null) {
+ hasFocusGoogleAccount = true;
+ break;
+ }
}
-
- final Preference licensePreference = findPreference(
- getString(R.string.pref_open_source_licenses_key));
- licensePreference.setIntent(new Intent(getActivity(), LicenseActivity.class));
+ if (!hasFocusGoogleAccount
+ || !MetadataSyncEnabledCompat.isMetadataSyncEnabled(getContext())) {
+ getPreferenceScreen().removePreference(findPreference("contactMetadata"));
+ }
}
@Override
diff --git a/src/com/android/contacts/commonbind/logging/ClearcutLoggerHelper.java b/src/com/android/contacts/commonbind/logging/ClearcutLoggerHelper.java
new file mode 100644
index 0000000..25c401c
--- /dev/null
+++ b/src/com/android/contacts/commonbind/logging/ClearcutLoggerHelper.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.contacts.commonbind.logging;
+
+import com.android.contacts.common.logging.Logger;
+import com.android.contacts.common.logging.SearchState;
+
+/**
+ * No-op clearcut logger implementation.
+ */
+public class ClearcutLoggerHelper extends Logger {
+
+ private static ClearcutLoggerHelper sInstance;
+
+ public static ClearcutLoggerHelper getInstance() {
+ if (sInstance == null) {
+ sInstance = new ClearcutLoggerHelper();
+ }
+ return sInstance;
+ }
+
+ private ClearcutLoggerHelper() {
+ }
+
+ @Override
+ public void logScreenViewImpl(int screenType) {
+ }
+
+ @Override
+ public void logSearchEventImpl(SearchState searchState) {
+ }
+}