diff options
author | Yorke Lee <yorkelee@google.com> | 2015-07-15 22:40:04 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-07-15 22:40:04 +0000 |
commit | 3abaae1a037f1764b4329dd6381b4c9e6ffa952a (patch) | |
tree | 4687a00a9b56a8c8e85c5291eaf11c32befd9baa | |
parent | 55fcb21595a4702029eb5695862ca2726f248649 (diff) | |
parent | 38019af70eb1ca084d36291390bbc54dc81027de (diff) | |
download | packages_apps_Dialer-3abaae1a037f1764b4329dd6381b4c9e6ffa952a.tar.gz packages_apps_Dialer-3abaae1a037f1764b4329dd6381b4c9e6ffa952a.tar.bz2 packages_apps_Dialer-3abaae1a037f1764b4329dd6381b4c9e6ffa952a.zip |
am 38019af7: Update Dialer UI to prompt for permissions
* commit '38019af70eb1ca084d36291390bbc54dc81027de':
Update Dialer UI to prompt for permissions
-rw-r--r-- | res/layout/call_log_fragment.xml | 3 | ||||
-rw-r--r-- | res/layout/empty_content_view.xml (renamed from res/layout/empty_list_view.xml) | 28 | ||||
-rw-r--r-- | res/layout/show_all_contacts_fragment.xml | 3 | ||||
-rw-r--r-- | res/layout/speed_dial_fragment.xml | 3 | ||||
-rw-r--r-- | res/values/styles.xml | 10 | ||||
-rw-r--r-- | src/com/android/dialer/DialtactsActivity.java | 21 | ||||
-rw-r--r-- | src/com/android/dialer/calllog/CallLogFragment.java | 95 | ||||
-rw-r--r-- | src/com/android/dialer/list/AllContactsFragment.java | 60 | ||||
-rw-r--r-- | src/com/android/dialer/list/EmptyContactsListAdapter.java | 47 | ||||
-rw-r--r-- | src/com/android/dialer/list/SpeedDialFragment.java | 37 | ||||
-rw-r--r-- | src/com/android/dialer/util/DialerUtils.java | 22 | ||||
-rw-r--r-- | src/com/android/dialer/widget/EmptyContentView.java | 102 |
12 files changed, 317 insertions, 114 deletions
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml index 68e306074..3a7013d57 100644 --- a/res/layout/call_log_fragment.xml +++ b/res/layout/call_log_fragment.xml @@ -27,11 +27,10 @@ android:paddingStart="@dimen/call_log_horizontal_margin" android:paddingEnd="@dimen/call_log_horizontal_margin" /> - <include + <com.android.dialer.widget.EmptyContentView android:id="@+id/empty_list_view" android:layout_width="match_parent" android:layout_height="match_parent" - layout="@layout/empty_list_view" android:visibility="gone" /> </FrameLayout> diff --git a/res/layout/empty_list_view.xml b/res/layout/empty_content_view.xml index 7f961a350..18633d0f9 100644 --- a/res/layout/empty_list_view.xml +++ b/res/layout/empty_content_view.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project +<!-- 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. @@ -13,15 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingTop="@dimen/empty_list_message_top_padding" - android:paddingBottom="@dimen/actionbar_and_tab_height" - android:minHeight="?android:attr/listPreferredItemHeight"> +<merge xmlns:android="http://schemas.android.com/apk/res/android"> <ImageView android:id="@+id/emptyListViewImage" android:layout_height="wrap_content" @@ -39,4 +32,19 @@ android:paddingRight="16dp" android:paddingLeft="16dp" /> -</LinearLayout> + <TextView + android:id="@+id/emptyListViewAction" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:layout_gravity="center_horizontal" + android:paddingRight="16dp" + android:paddingLeft="16dp" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:text="@string/permission_single_turn_on" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + style="@style/TextActionStyle" /> + +</merge> diff --git a/res/layout/show_all_contacts_fragment.xml b/res/layout/show_all_contacts_fragment.xml index 00358dc47..3b501fb88 100644 --- a/res/layout/show_all_contacts_fragment.xml +++ b/res/layout/show_all_contacts_fragment.xml @@ -44,11 +44,10 @@ android:nestedScrollingEnabled="true" /> </FrameLayout> - <include + <com.android.dialer.widget.EmptyContentView android:id="@+id/empty_list_view" android:layout_width="match_parent" android:layout_height="match_parent" - layout="@layout/empty_list_view" android:visibility="gone"/> </LinearLayout> diff --git a/res/layout/speed_dial_fragment.xml b/res/layout/speed_dial_fragment.xml index 18820497e..55dd158d2 100644 --- a/res/layout/speed_dial_fragment.xml +++ b/res/layout/speed_dial_fragment.xml @@ -41,11 +41,10 @@ android:nestedScrollingEnabled="true" /> </FrameLayout> - <include + <com.android.dialer.widget.EmptyContentView android:id="@+id/empty_list_view" android:layout_width="match_parent" android:layout_height="match_parent" - layout="@layout/empty_list_view" android:visibility="gone"/> </FrameLayout> diff --git a/res/values/styles.xml b/res/values/styles.xml index 957fabf86..e3a2f9974 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -218,20 +218,24 @@ <item name="cardBackgroundColor">@color/background_dialer_call_log_list_item</item> </style> - <style name="PromoCardActionStyle"> + <style name="TextActionStyle"> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">@dimen/call_log_action_height</item> <item name="android:gravity">end|center_vertical</item> <item name="android:paddingStart">@dimen/call_log_action_horizontal_padding</item> <item name="android:paddingEnd">@dimen/call_log_action_horizontal_padding</item> - <item name="android:textColor">@color/promo_card_text</item> - <item name="android:textSize">@dimen/call_log_list_item_actions_text_size</item> + <item name="android:textColor">@color/dialtacts_theme_color</item> <item name="android:fontFamily">"sans-serif-medium"</item> <item name="android:focusable">true</item> <item name="android:singleLine">true</item> <item name="android:textAllCaps">true</item> </style> + <style name="PromoCardActionStyle" parent="TextActionStyle"> + <item name="android:textColor">@color/promo_card_text</item> + <item name="android:textSize">@dimen/call_log_list_item_actions_text_size</item> + </style> + <style name="VoicemailPlaybackLayoutTextStyle"> <item name="android:textSize">14sp</item> </style> diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index 31d1b94bf..85197a530 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -66,6 +66,7 @@ import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.widget.FloatingActionButtonController; import com.android.contacts.commonbind.analytics.AnalyticsUtil; import com.android.dialer.calllog.CallLogActivity; +import com.android.dialer.calllog.CallLogFragment; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpad.DialpadFragment; import com.android.dialer.dialpad.SmartDialNameMatcher; @@ -101,6 +102,7 @@ import java.util.List; public class DialtactsActivity extends TransactionSafeActivity implements View.OnClickListener, DialpadFragment.OnDialpadQueryChangedListener, OnListFragmentScrolledListener, + CallLogFragment.HostInterface, ListsFragment.HostInterface, SpeedDialFragment.HostInterface, SearchFragment.HostInterface, @@ -1207,6 +1209,24 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mListsFragment.getRemoveView().setDragDropController(dragController); } + /** + * Implemented to satisfy {@link SpeedDialFragment.HostInterface} + */ + @Override + public void showAllContactsTab() { + if (mListsFragment != null) { + mListsFragment.showTab(ListsFragment.TAB_INDEX_ALL_CONTACTS); + } + } + + /** + * Implemented to satisfy {@link CallLogFragment.HostInterface} + */ + @Override + public void showDialpad() { + showDialpadFragment(true); + } + @Override public void onPickPhoneNumberAction(Uri dataUri) { // Specify call-origin so that users will see the previous tab instead of @@ -1322,7 +1342,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O return mActionBarHeight; } - private int getFabAlignment() { if (!mIsLandscape && !isInSearchUi() && mListsFragment.getCurrentTabIndex() == ListsFragment.TAB_INDEX_SPEED_DIAL) { diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java index 5d7c408ce..d1a9827eb 100644 --- a/src/com/android/dialer/calllog/CallLogFragment.java +++ b/src/com/android/dialer/calllog/CallLogFragment.java @@ -16,6 +16,8 @@ package com.android.dialer.calllog; +import static android.Manifest.permission.READ_CALL_LOG; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -26,6 +28,7 @@ import android.app.KeyguardManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.database.Cursor; import android.graphics.Rect; @@ -46,6 +49,7 @@ import android.widget.ListView; import android.widget.TextView; import com.android.contacts.common.GeoUtil; +import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.ViewUtil; import com.android.dialer.R; import com.android.dialer.list.ListsFragment.HostInterface; @@ -55,6 +59,8 @@ import com.android.dialer.voicemail.VoicemailPlaybackPresenter; import com.android.dialer.voicemail.VoicemailStatusHelper; import com.android.dialer.voicemail.VoicemailStatusHelper.StatusMessage; import com.android.dialer.voicemail.VoicemailStatusHelperImpl; +import com.android.dialer.widget.EmptyContentView; +import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; import com.android.dialerbind.ObjectFactory; import java.util.List; @@ -63,8 +69,8 @@ import java.util.List; * Displays a list of call log entries. To filter for a particular kind of call * (all, missed or voicemails), specify it in the constructor. */ -public class CallLogFragment extends Fragment - implements CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher { +public class CallLogFragment extends Fragment implements CallLogQueryHandler.Listener, + CallLogAdapter.CallFetcher, OnEmptyViewActionButtonClickedListener { private static final String TAG = "CallLogFragment"; /** @@ -81,6 +87,8 @@ public class CallLogFragment extends Fragment // No date-based filtering. private static final int NO_DATE_LIMIT = 0; + private static final int READ_CALL_LOG_PERMISSION_REQUEST_CODE = 1; + private RecyclerView mRecyclerView; private LinearLayoutManager mLayoutManager; private CallLogAdapter mAdapter; @@ -91,7 +99,7 @@ public class CallLogFragment extends Fragment /** Whether there is at least one voicemail source installed. */ private boolean mVoicemailSourcesAvailable = false; - private View mEmptyListView; + private EmptyContentView mEmptyListView; private KeyguardManager mKeyguardManager; private boolean mEmptyLoaderRunning; @@ -116,6 +124,8 @@ public class CallLogFragment extends Fragment private final ContentObserver mVoicemailStatusObserver = new CustomContentObserver(); private boolean mRefreshDataRequired = true; + private boolean mHasReadCallLogPermission = false; + // Exactly same variable is in Fragment as a package private. private boolean mMenuVisible = true; @@ -130,6 +140,16 @@ public class CallLogFragment extends Fragment // the date filter are included. If zero, no date-based filtering occurs. private long mDateLimit = NO_DATE_LIMIT; + /* + * True if this instance of the CallLogFragment is the Recents screen shown in + * DialtactsActivity. + */ + private boolean mIsRecentsFragment; + + public interface HostInterface { + public void showDialpad(); + } + public CallLogFragment() { this(CallLogQueryHandler.CALL_TYPE_ALL, NO_LOG_LIMIT); } @@ -139,9 +159,7 @@ public class CallLogFragment extends Fragment } public CallLogFragment(int filterType, int logLimit) { - super(); - mCallTypeFilter = filterType; - mLogLimit = logLimit; + this(filterType, logLimit, NO_DATE_LIMIT); } /** @@ -162,7 +180,8 @@ public class CallLogFragment extends Fragment * @param dateLimit limits results to calls occurring on or after the specified date. */ public CallLogFragment(int filterType, int logLimit, long dateLimit) { - this(filterType, logLimit); + mCallTypeFilter = filterType; + mLogLimit = logLimit; mDateLimit = dateLimit; } @@ -175,6 +194,8 @@ public class CallLogFragment extends Fragment mDateLimit = state.getLong(KEY_DATE_LIMIT, mDateLimit); } + mIsRecentsFragment = mLogLimit != NO_LOG_LIMIT; + final Activity activity = getActivity(); final ContentResolver resolver = activity.getContentResolver(); String currentCountryIso = GeoUtil.getCurrentCountryIso(activity); @@ -268,7 +289,9 @@ public class CallLogFragment extends Fragment mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mLayoutManager); - mEmptyListView = view.findViewById(R.id.empty_list_view); + mEmptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view); + mEmptyListView.setImage(R.drawable.empty_call_log); + mEmptyListView.setActionClickedListener(this); String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity()); boolean isShowingRecentsTab = mLogLimit != NO_LOG_LIMIT || mDateLimit != NO_DATE_LIMIT; @@ -287,7 +310,6 @@ public class CallLogFragment extends Fragment @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - updateEmptyMessage(mCallTypeFilter); mAdapter.onRestoreInstanceState(savedInstanceState); } @@ -305,6 +327,16 @@ public class CallLogFragment extends Fragment @Override public void onResume() { super.onResume(); + final boolean hasReadCallLogPermission = + PermissionsUtil.hasPermission(getActivity(), READ_CALL_LOG); + if (!mHasReadCallLogPermission && hasReadCallLogPermission) { + // We didn't have the permission before, and now we do. Force a refresh of the call log. + // Note that this code path always happens on a fresh start, but mRefreshDataRequired + // is already true in that case anyway. + mRefreshDataRequired = true; + updateEmptyMessage(mCallTypeFilter); + } + mHasReadCallLogPermission = hasReadCallLogPermission; refreshData(); } @@ -359,6 +391,17 @@ public class CallLogFragment extends Fragment } private void updateEmptyMessage(int filterType) { + final Context context = getActivity(); + if (context == null) { + return; + } + + if (!PermissionsUtil.hasPermission(context, READ_CALL_LOG)) { + mEmptyListView.setDescription(R.string.permission_no_calllog); + mEmptyListView.setActionLabel(R.string.permission_single_turn_on); + return; + } + final int messageId; switch (filterType) { case Calls.MISSED_TYPE: @@ -374,8 +417,12 @@ public class CallLogFragment extends Fragment throw new IllegalArgumentException("Unexpected filter type in CallLogFragment: " + filterType); } - DialerUtils.configureEmptyListView( - mEmptyListView, R.drawable.empty_call_log, messageId, getResources()); + mEmptyListView.setDescription(messageId); + if (mIsRecentsFragment) { + mEmptyListView.setActionLabel(R.string.recentCalls_empty_action); + } else { + mEmptyListView.setActionLabel(EmptyContentView.NO_LABEL); + } } CallLogAdapter getAdapter() { @@ -437,4 +484,30 @@ public class CallLogFragment extends Fragment CallLogNotificationsHelper.updateVoicemailNotifications(getActivity()); } } + + @Override + public void onEmptyViewActionButtonClicked(String[] permissions) { + final Activity activity = getActivity(); + if (activity == null) { + return; + } + + if (!PermissionsUtil.hasPermission(activity, READ_CALL_LOG)) { + requestPermissions(new String[] {READ_CALL_LOG}, READ_CALL_LOG_PERMISSION_REQUEST_CODE); + } else if (mIsRecentsFragment) { + // Show dialpad if we are the recents fragment. + ((HostInterface) activity).showDialpad(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, + int[] grantResults) { + if (requestCode == READ_CALL_LOG_PERMISSION_REQUEST_CODE) { + if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) { + // Force a refresh of the data since we were missing the permission before this. + mRefreshDataRequired = true; + } + } + } } diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java index d34250b48..00b629c2b 100644 --- a/src/com/android/dialer/list/AllContactsFragment.java +++ b/src/com/android/dialer/list/AllContactsFragment.java @@ -16,7 +16,11 @@ package com.android.dialer.list; +import static android.Manifest.permission.READ_CONTACTS; + +import android.app.Activity; import android.content.Loader; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract.CommonDataKinds.Phone; @@ -34,13 +38,19 @@ import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.ViewUtil; import com.android.dialer.R; import com.android.dialer.util.DialerUtils; +import com.android.dialer.util.IntentUtil; +import com.android.dialer.widget.EmptyContentView; +import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; /** * Fragments to show all contacts with phone numbers. */ -public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter> { +public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter> + implements OnEmptyViewActionButtonClickedListener { + + private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1; - private View mEmptyListView; + private EmptyContentView mEmptyListView; public AllContactsFragment() { setQuickContactEnabled(false); @@ -55,9 +65,10 @@ public class AllContactsFragment extends ContactEntryListFragment<ContactEntryLi public void onViewCreated(View view, android.os.Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - mEmptyListView = view.findViewById(R.id.empty_list_view); - DialerUtils.configureEmptyListView(mEmptyListView, R.drawable.empty_contacts, - R.string.all_contacts_empty, getResources()); + mEmptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view); + mEmptyListView.setImage(R.drawable.empty_contacts); + mEmptyListView.setDescription(R.string.all_contacts_empty); + mEmptyListView.setActionClickedListener(this); getListView().setEmptyView(mEmptyListView); mEmptyListView.setVisibility(View.GONE); @@ -66,8 +77,14 @@ public class AllContactsFragment extends ContactEntryListFragment<ContactEntryLi @Override protected void startLoading() { - if (PermissionsUtil.hasContactsPermissions(getActivity())) { + if (PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) { super.startLoading(); + mEmptyListView.setDescription(R.string.all_contacts_empty); + mEmptyListView.setActionLabel(R.string.all_contacts_empty_add_contact_action); + } else { + mEmptyListView.setDescription(R.string.permission_no_contacts); + mEmptyListView.setActionLabel(R.string.permission_single_turn_on); + mEmptyListView.setVisibility(View.VISIBLE); } } @@ -82,10 +99,6 @@ public class AllContactsFragment extends ContactEntryListFragment<ContactEntryLi @Override protected ContactEntryListAdapter createListAdapter() { - if (!PermissionsUtil.hasContactsPermissions(getActivity())) { - return new EmptyContactsListAdapter(getActivity()); - } - final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()) { @Override protected void bindView(View itemView, int partition, Cursor cursor, int position) { @@ -118,4 +131,31 @@ public class AllContactsFragment extends ContactEntryListFragment<ContactEntryLi protected void onItemClick(int position, long id) { // Do nothing. Implemented to satisfy ContactEntryListFragment. } + + @Override + public void onEmptyViewActionButtonClicked(String[] permissions) { + final Activity activity = getActivity(); + if (activity == null) { + return; + } + + if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) { + requestPermissions(new String[] {READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE); + } else { + // Add new contact + DialerUtils.startActivityWithErrorToast(activity, IntentUtil.getNewContactIntent(), + R.string.add_contact_not_available); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, + int[] grantResults) { + if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) { + if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) { + // Force a refresh of the data since we were missing the permission before this. + reloadData(); + } + } + } } diff --git a/src/com/android/dialer/list/EmptyContactsListAdapter.java b/src/com/android/dialer/list/EmptyContactsListAdapter.java deleted file mode 100644 index 54bd4771f..000000000 --- a/src/com/android/dialer/list/EmptyContactsListAdapter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.dialer.list; - -import android.content.Context; -import android.content.CursorLoader; - -import com.android.contacts.common.list.ContactEntryListAdapter; - -/** - * Used to display an empty contact list when we don't have the permissions to read contacts. - */ -public class EmptyContactsListAdapter extends ContactEntryListAdapter { - - public EmptyContactsListAdapter(Context context) { - super(context); - } - - @Override - public String getContactDisplayName(int position) { - return null; - } - - @Override - public void configureLoader(CursorLoader loader, long directoryId) { - loader.setUri(null); - } - - @Override - public int getCount() { - return 0; - } -} diff --git a/src/com/android/dialer/list/SpeedDialFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java index bf9575858..aead1c81b 100644 --- a/src/com/android/dialer/list/SpeedDialFragment.java +++ b/src/com/android/dialer/list/SpeedDialFragment.java @@ -15,6 +15,8 @@ */ package com.android.dialer.list; +import static android.Manifest.permission.READ_CONTACTS; + import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; @@ -50,6 +52,7 @@ import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; import com.android.contacts.common.util.PermissionsUtil; import com.android.dialer.R; import com.android.dialer.util.DialerUtils; +import com.android.dialer.widget.EmptyContentView; import java.util.ArrayList; import java.util.HashMap; @@ -58,7 +61,8 @@ import java.util.HashMap; * This fragment displays the user's favorite/frequent contacts in a grid. */ public class SpeedDialFragment extends Fragment implements OnItemClickListener, - PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener { + PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener, + EmptyContentView.OnEmptyViewActionButtonClickedListener { /** * By default, the animation code assumes that all items in a list view are of the same height @@ -81,6 +85,7 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, public interface HostInterface { public void setDragDropController(DragDropController controller); + public void showAllContactsTab(); } private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> { @@ -157,7 +162,7 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, /** * Layout used when there are no favorites. */ - private View mEmptyView; + private EmptyContentView mEmptyView; private final ContactTileView.Listener mContactTileAdapterListener = new ContactTileAdapterListener(); @@ -197,9 +202,16 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, if (getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE) == null) { getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener); + } else { getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad(); } + + mEmptyView.setDescription(R.string.speed_dial_empty); + mEmptyView.setActionLabel(R.string.speed_dial_empty_add_favorite_action); + } else { + mEmptyView.setDescription(R.string.permission_no_speeddial); + mEmptyView.setActionLabel(R.string.permission_single_turn_on); } Trace.endSection(); } @@ -221,9 +233,9 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, (ImageView) getActivity().findViewById(R.id.contact_tile_drag_shadow_overlay); mListView.setDragShadowOverlay(dragShadowOverlay); - mEmptyView = mParentView.findViewById(R.id.empty_list_view); - DialerUtils.configureEmptyListView( - mEmptyView, R.drawable.empty_speed_dial, R.string.speed_dial_empty, getResources()); + mEmptyView = (EmptyContentView) mParentView.findViewById(R.id.empty_list_view); + mEmptyView.setImage(R.drawable.empty_speed_dial); + mEmptyView.setActionClickedListener(this); mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame); @@ -449,4 +461,19 @@ public class SpeedDialFragment extends Fragment implements OnItemClickListener, public AbsListView getListView() { return mListView; } + + @Override + public void onEmptyViewActionButtonClicked(String[] permissions) { + final Activity activity = getActivity(); + if (activity == null) { + return; + } + + if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) { + requestPermissions(new String[] {READ_CONTACTS}, 0); + } else { + // Switch tabs + ((HostInterface) activity).showAllContactsTab(); + } + } } diff --git a/src/com/android/dialer/util/DialerUtils.java b/src/com/android/dialer/util/DialerUtils.java index a44c2eec6..e25ada59d 100644 --- a/src/com/android/dialer/util/DialerUtils.java +++ b/src/com/android/dialer/util/DialerUtils.java @@ -40,6 +40,7 @@ import android.widget.Toast; import com.android.contacts.common.ContactsUtils; import com.android.contacts.common.interactions.TouchPointManager; import com.android.dialer.R; +import com.android.dialer.widget.EmptyContentView; import com.android.incallui.CallCardFragment; import com.android.incallui.Log; @@ -116,27 +117,6 @@ public class DialerUtils { } /** - * Sets the image asset and text for an empty list view (see empty_list_view.xml). - * - * @param emptyListView The empty list view. - * @param imageResId The resource id for the drawable to set as the image. - * @param strResId The resource id for the string to set as the message. - * @param res The resources to obtain the image and string from. - */ - public static void configureEmptyListView( - View emptyListView, int imageResId, int strResId, Resources res) { - ImageView emptyListViewImage = - (ImageView) emptyListView.findViewById(R.id.emptyListViewImage); - - emptyListViewImage.setImageDrawable(res.getDrawable(imageResId)); - emptyListViewImage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - - TextView emptyListViewMessage = - (TextView) emptyListView.findViewById(R.id.emptyListViewMessage); - emptyListViewMessage.setText(res.getString(strResId)); - } - - /** * Closes an {@link AutoCloseable}, silently ignoring any checked exceptions. Does nothing if * null. * diff --git a/src/com/android/dialer/widget/EmptyContentView.java b/src/com/android/dialer/widget/EmptyContentView.java new file mode 100644 index 000000000..67c9ce15f --- /dev/null +++ b/src/com/android/dialer/widget/EmptyContentView.java @@ -0,0 +1,102 @@ +/* + * 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.dialer.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.dialer.R; + +public class EmptyContentView extends LinearLayout implements View.OnClickListener { + + public static final int NO_LABEL = 0; + + private ImageView mImageView; + private TextView mDescriptionView; + private TextView mActionView; + private String[] mPermissions = new String[] {}; + private OnEmptyViewActionButtonClickedListener mOnActionButtonClickedListener; + + public interface OnEmptyViewActionButtonClickedListener { + public void onEmptyViewActionButtonClicked(String[] permissions); + } + + public EmptyContentView(Context context) { + this(context, null); + } + + public EmptyContentView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public EmptyContentView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public EmptyContentView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + setOrientation(LinearLayout.VERTICAL); + + final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.empty_content_view, this); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mImageView = (ImageView) findViewById(R.id.emptyListViewImage); + mDescriptionView = (TextView) findViewById(R.id.emptyListViewMessage); + mActionView = (TextView) findViewById(R.id.emptyListViewAction); + mActionView.setOnClickListener(this); + } + + public void setDescription(int resourceId) { + mDescriptionView.setText(resourceId); + } + + public void setImage(int resourceId) { + mImageView.setImageResource(resourceId); + } + + public void setActionLabel(int resourceId) { + if (resourceId == NO_LABEL) { + mActionView.setText(null); + mActionView.setVisibility(View.GONE); + } else { + mActionView.setText(resourceId); + mActionView.setVisibility(View.VISIBLE); + } + } + + public void setActionClickedListener(OnEmptyViewActionButtonClickedListener listener) { + mOnActionButtonClickedListener = listener; + } + + @Override + public void onClick(View v) { + if (mOnActionButtonClickedListener != null) { + mOnActionButtonClickedListener.onEmptyViewActionButtonClicked(mPermissions); + } + } +} |