diff options
Diffstat (limited to 'java/com/android/dialer/calllog')
5 files changed, 102 insertions, 9 deletions
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java index a08b50eb8..1b66f5099 100644 --- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java +++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java @@ -62,11 +62,13 @@ import java.util.Arrays; import java.util.List; import java.util.Set; import javax.inject.Inject; +import javax.inject.Singleton; /** * Responsible for defining the rows in the annotated call log and maintaining the columns in it * which are derived from the system call log. */ +@Singleton @SuppressWarnings("MissingPermission") public class SystemCallLogDataSource implements CallLogDataSource { @@ -81,6 +83,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { private final Duo duo; @Nullable private Long lastTimestampProcessed; + private boolean isCallLogContentObserverRegistered = false; @Inject SystemCallLogDataSource( @@ -106,7 +109,6 @@ public class SystemCallLogDataSource implements CallLogDataSource { LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no call log permissions"); return; } - // TODO(zachh): Need to somehow register observers if user enables permission after launch? // The system call log has a last updated timestamp, but deletes are physical (the "deleted" // column is unused). This means that we can't detect deletes without scanning the entire table, @@ -115,6 +117,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { appContext .getContentResolver() .registerContentObserver(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL, true, markDirtyObserver); + isCallLogContentObserverRegistered = true; if (!PermissionsUtil.hasAddVoicemailPermissions(appContext)) { LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no add voicemail permissions"); @@ -129,6 +132,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { @Override public void unregisterContentObservers() { appContext.getContentResolver().unregisterContentObserver(markDirtyObserver); + isCallLogContentObserverRegistered = false; } @Override @@ -140,7 +144,6 @@ public class SystemCallLogDataSource implements CallLogDataSource { return null; }); - // TODO(zachh): Test re-enabling after deleting database like this. return Futures.transform( Futures.allAsList(deleteSharedPref, annotatedCallLogDatabaseHelper.delete()), unused -> null, @@ -154,6 +157,14 @@ public class SystemCallLogDataSource implements CallLogDataSource { @Override public ListenableFuture<Boolean> isDirty() { + // This can happen if the call log permission is enabled after the application is started. + if (!isCallLogContentObserverRegistered + && PermissionsUtil.hasCallLogReadPermissions(appContext)) { + registerContentObservers(); + // Consider the data source dirty because calls could have been missed while the content + // observer wasn't registered. + return Futures.immediateFuture(true); + } return backgroundExecutorService.submit(this::isDirtyInternal); } diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java index 1890b7433..2feed4068 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java @@ -21,6 +21,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.support.v4.content.LocalBroadcastManager; @@ -41,18 +42,26 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.metrics.Metrics; import com.android.dialer.metrics.MetricsComponent; import com.android.dialer.metrics.jank.RecyclerViewJankLogger; +import com.android.dialer.util.PermissionsUtil; +import com.android.dialer.widget.EmptyContentView; +import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import java.util.Arrays; import java.util.concurrent.TimeUnit; /** The "new" call log fragment implementation, which is built on top of the annotated call log. */ public final class NewCallLogFragment extends Fragment implements LoaderCallbacks<Cursor> { + private static final int PHONE_PERMISSIONS_REQUEST_CODE = 1; + private static final int LOADER_ID = 0; + @VisibleForTesting static final long MARK_ALL_CALLS_READ_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3); private RecyclerView recyclerView; + private EmptyContentView emptyContentView; private RefreshAnnotatedCallLogReceiver refreshAnnotatedCallLogReceiver; private SupportUiListener<Cursor> coalesingAnnotatedCallLogListener; @@ -133,6 +142,22 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback * will be called but it is not visible. */ private void onFragmentShown() { + LoaderManager loaderManager = getLoaderManager(); + if (!PermissionsUtil.hasCallLogReadPermissions(getContext())) { + recyclerView.setVisibility(View.GONE); + emptyContentView.setVisibility(View.VISIBLE); + loaderManager.destroyLoader(LOADER_ID); + return; + } + + recyclerView.setVisibility(View.VISIBLE); + emptyContentView.setVisibility(View.GONE); + + // This can happen if permissions were not enabled when the fragment was created. + if (loaderManager.getLoader(LOADER_ID) == null) { + loaderManager.restartLoader(LOADER_ID, null, this); + } + registerRefreshAnnotatedCallLogReceiver(); CallLogComponent.get(getContext()) @@ -193,16 +218,53 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback new RecyclerViewJankLogger( MetricsComponent.get(getContext()).metrics(), Metrics.NEW_CALL_LOG_JANK_EVENT_NAME)); + emptyContentView = view.findViewById(R.id.new_call_log_empty_content_view); + configureEmptyContentView(); + coalesingAnnotatedCallLogListener = DialerExecutorComponent.get(getContext()) .createUiListener( getChildFragmentManager(), /* taskId = */ "NewCallLogFragment.coalescingAnnotatedCallLog"); - getLoaderManager().restartLoader(0, null, this); + + if (PermissionsUtil.hasCallLogReadPermissions(getContext())) { + getLoaderManager().restartLoader(LOADER_ID, null, this); + } return view; } + private void configureEmptyContentView() { + emptyContentView.setImage(R.drawable.quantum_ic_query_builder_vd_theme_24); + emptyContentView.setImageTint(R.color.empty_call_log_icon_tint_color, null); + emptyContentView.setDescription(R.string.new_call_log_permission_no_calllog); + emptyContentView.setActionLabel(com.android.dialer.widget.R.string.permission_single_turn_on); + emptyContentView.setActionClickedListener(new TurnOnPhonePermissions()); + } + + private class TurnOnPhonePermissions implements OnEmptyViewActionButtonClickedListener { + + @Override + public void onEmptyViewActionButtonClicked() { + if (getContext() == null) { + LogUtil.w("TurnOnPhonePermissions.onEmptyViewActionButtonClicked", "no context"); + return; + } + String[] deniedPermissions = + PermissionsUtil.getPermissionsCurrentlyDenied( + getContext(), PermissionsUtil.allPhoneGroupPermissionsUsedInDialer); + if (deniedPermissions.length > 0) { + LogUtil.i( + "TurnOnPhonePermissions.onEmptyViewActionButtonClicked", + "requesting permissions: %s", + Arrays.toString(deniedPermissions)); + // Don't implement onRequestPermissionsResult; instead rely on views being updated in + // #onFragmentShown. + requestPermissions(deniedPermissions, PHONE_PERMISSIONS_REQUEST_CODE); + } + } + } + private void registerRefreshAnnotatedCallLogReceiver() { LogUtil.enterBlock("NewCallLogFragment.registerRefreshAnnotatedCallLogReceiver"); diff --git a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml index 048d562d3..1a2ec22d6 100644 --- a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml +++ b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml @@ -15,11 +15,26 @@ ~ limitations under the License --> -<android.support.v7.widget.RecyclerView +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/new_call_log_recycler_view" - android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/background_dialer_white" - android:paddingBottom="@dimen/floating_action_button_list_bottom_padding" - android:clipToPadding="false"/> + android:layout_width="match_parent"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/new_call_log_recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingBottom="@dimen/floating_action_button_list_bottom_padding" + android:background="@color/background_dialer_white" + android:clipToPadding="false"/> + + <com.android.dialer.widget.EmptyContentView + android:gravity="center_vertical" + android:id="@+id/new_call_log_empty_content_view" + android:background="@color/background_dialer_white" + android:layout_gravity="center" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:visibility="gone"/> + +</FrameLayout> diff --git a/java/com/android/dialer/calllog/ui/res/values/colors.xml b/java/com/android/dialer/calllog/ui/res/values/colors.xml index 0a6d512ef..002aaf959 100644 --- a/java/com/android/dialer/calllog/ui/res/values/colors.xml +++ b/java/com/android/dialer/calllog/ui/res/values/colors.xml @@ -21,4 +21,6 @@ <color name="call_type_icon_read_color">#757575</color> <color name="call_type_icon_unread_color">#D32F2F</color> + + <color name="empty_call_log_icon_tint_color">#E1E1E1</color> </resources>
\ No newline at end of file diff --git a/java/com/android/dialer/calllog/ui/res/values/strings.xml b/java/com/android/dialer/calllog/ui/res/values/strings.xml index ec8d59503..699dfe9a6 100644 --- a/java/com/android/dialer/calllog/ui/res/values/strings.xml +++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml @@ -36,4 +36,7 @@ Google Duo video calling lets you chat with friends and family face-to-face. Data charges may apply. <xliff:g example="Learn More">%1$s</xliff:g> </string> + <!-- Shown as a prompt to turn on the phone permission to enable the call log [CHAR LIMIT=NONE]--> + <string name="new_call_log_permission_no_calllog">To see your call log, turn on the Phone permission.</string> + </resources> |