diff options
Diffstat (limited to 'java')
6 files changed, 265 insertions, 22 deletions
diff --git a/java/com/android/dialer/calllog/ui/DuoDisclosureCardViewHolder.java b/java/com/android/dialer/calllog/ui/DuoDisclosureCardViewHolder.java new file mode 100644 index 000000000..6b9112789 --- /dev/null +++ b/java/com/android/dialer/calllog/ui/DuoDisclosureCardViewHolder.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 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.calllog.ui; + +import android.content.Context; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.dialer.configprovider.ConfigProviderBindings; +import com.android.dialer.duo.DuoComponent; +import com.android.dialer.spannable.ContentWithLearnMoreSpanner; + +/** ViewHolder for {@link NewCallLogAdapter} to display the Duo disclosure card. */ +public class DuoDisclosureCardViewHolder extends ViewHolder { + + private final Button okButton; + + DuoDisclosureCardViewHolder(View itemView) { + super(itemView); + + Context context = itemView.getContext(); + + // Set the Duo logo. + ImageView duoLogoView = itemView.findViewById(R.id.new_call_log_duo_disclosure_card_logo); + duoLogoView.setImageResource(DuoComponent.get(context).getDuo().getLogo()); + + // Set detailed text with a "learn more" link. + TextView cardDetailsView = itemView.findViewById(R.id.new_call_log_duo_disclosure_card_details); + cardDetailsView.setText( + new ContentWithLearnMoreSpanner(context) + .create( + context.getResources().getString(R.string.new_call_log_duo_disclosure_card_details), + ConfigProviderBindings.get(context) + .getString( + "duo_disclosure_link_full_url", + "http://support.google.com/pixelphone/?p=dialer_duo"))); + cardDetailsView.setMovementMethod(LinkMovementMethod.getInstance()); // make the link clickable + + // Obtain a reference to the "OK, got it" button. + okButton = itemView.findViewById(R.id.new_call_log_duo_disclosure_card_ok); + } + + void setDismissListener(OnClickListener listener) { + okButton.setOnClickListener(listener); + } +} diff --git a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java index 839ba332f..22163774e 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java @@ -16,16 +16,21 @@ package com.android.dialer.calllog.ui; import android.content.Context; +import android.content.SharedPreferences; import android.database.Cursor; import android.support.annotation.IntDef; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.LayoutInflater; import android.view.ViewGroup; import com.android.dialer.calllogutils.CallLogDates; import com.android.dialer.common.Assert; +import com.android.dialer.duo.Duo; +import com.android.dialer.duo.DuoComponent; import com.android.dialer.logging.Logger; +import com.android.dialer.storage.StorageComponent; import com.android.dialer.time.Clock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -33,31 +38,45 @@ import java.lang.annotation.RetentionPolicy; /** {@link RecyclerView.Adapter} for the new call log fragment. */ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { + @VisibleForTesting + static final String SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED = "duo_disclosure_dismissed"; + /** IntDef for the different types of rows that can be shown in the call log. */ @Retention(RetentionPolicy.SOURCE) @IntDef({ + RowType.DUO_DISCLOSURE_CARD, RowType.HEADER_TODAY, RowType.HEADER_YESTERDAY, RowType.HEADER_OLDER, RowType.CALL_LOG_ENTRY }) @interface RowType { + /** The Duo disclosure card. */ + int DUO_DISCLOSURE_CARD = 1; + /** Header that displays "Today". */ - int HEADER_TODAY = 1; + int HEADER_TODAY = 2; + /** Header that displays "Yesterday". */ - int HEADER_YESTERDAY = 2; + int HEADER_YESTERDAY = 3; + /** Header that displays "Older". */ - int HEADER_OLDER = 3; + int HEADER_OLDER = 4; + /** A row representing a call log entry (which could represent one or more calls). */ - int CALL_LOG_ENTRY = 4; + int CALL_LOG_ENTRY = 5; } private final Clock clock; + private final Context context; private final RealtimeRowProcessor realtimeRowProcessor; private final PopCounts popCounts = new PopCounts(); private Cursor cursor; + /** Position of the Duo disclosure card. Null when it should not be displayed. */ + @Nullable private Integer duoDisclosureCardPosition; + /** Position of the "Today" header. Null when it should not be displayed. */ @Nullable private Integer todayHeaderPosition; @@ -68,11 +87,12 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { @Nullable private Integer olderHeaderPosition; NewCallLogAdapter(Context context, Cursor cursor, Clock clock) { + this.context = context; this.cursor = cursor; this.clock = clock; this.realtimeRowProcessor = CallLogUiComponent.get(context).realtimeRowProcessor(); - setHeaderPositions(); + setCardAndHeaderPositions(); } void updateCursor(Cursor updatedCursor) { @@ -80,7 +100,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { this.realtimeRowProcessor.clearCache(); this.popCounts.reset(); - setHeaderPositions(); + setCardAndHeaderPositions(); notifyDataSetChanged(); } @@ -92,7 +112,15 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { Logger.get(context).logAnnotatedCallLogMetrics(popCounts.popped, popCounts.didNotPop); } - private void setHeaderPositions() { + private void setCardAndHeaderPositions() { + // Set the position for the Duo disclosure card if it should be shown. + duoDisclosureCardPosition = null; + int numCards = 0; + if (shouldShowDuoDisclosureCard()) { + duoDisclosureCardPosition = 0; + numCards++; + } + // If there are no rows to display, set all header positions to null. if (!cursor.moveToFirst()) { todayHeaderPosition = null; @@ -101,6 +129,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { return; } + // Calculate positions for headers. long currentTimeMillis = clock.currentTimeMillis(); int numItemsInToday = 0; @@ -126,24 +155,42 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { // Set all header positions. // A header position will be null if there is no item to be displayed under that header. - todayHeaderPosition = numItemsInToday > 0 ? 0 : null; - yesterdayHeaderPosition = numItemsInYesterday > 0 ? numItemsInToday : null; - olderHeaderPosition = !cursor.isAfterLast() ? numItemsInToday + numItemsInYesterday : null; + todayHeaderPosition = numItemsInToday > 0 ? numCards : null; + yesterdayHeaderPosition = numItemsInYesterday > 0 ? numItemsInToday + numCards : null; + olderHeaderPosition = + !cursor.isAfterLast() ? numItemsInToday + numItemsInYesterday + numCards : null; + } + + private boolean shouldShowDuoDisclosureCard() { + Duo duo = DuoComponent.get(context).getDuo(); + if (!duo.isEnabled(context) || !duo.isActivated(context)) { + return false; + } + + SharedPreferences sharedPref = StorageComponent.get(context).unencryptedSharedPrefs(); + return !sharedPref.getBoolean(SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED, false); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType) { switch (viewType) { + case RowType.DUO_DISCLOSURE_CARD: + return new DuoDisclosureCardViewHolder( + LayoutInflater.from(context) + .inflate( + R.layout.new_call_log_duo_disclosure_card, + viewGroup, + /* attachToRoot = */ false)); case RowType.HEADER_TODAY: case RowType.HEADER_YESTERDAY: case RowType.HEADER_OLDER: return new HeaderViewHolder( - LayoutInflater.from(viewGroup.getContext()) - .inflate(R.layout.new_call_log_header, viewGroup, false)); + LayoutInflater.from(context) + .inflate(R.layout.new_call_log_header, viewGroup, /* attachToRoot = */ false)); case RowType.CALL_LOG_ENTRY: return new NewCallLogViewHolder( - LayoutInflater.from(viewGroup.getContext()) - .inflate(R.layout.new_call_log_entry, viewGroup, false), + LayoutInflater.from(context) + .inflate(R.layout.new_call_log_entry, viewGroup, /* attachToRoot = */ false), clock, realtimeRowProcessor, popCounts); @@ -156,6 +203,19 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { public void onBindViewHolder(ViewHolder viewHolder, int position) { @RowType int viewType = getItemViewType(position); switch (viewType) { + case RowType.DUO_DISCLOSURE_CARD: + ((DuoDisclosureCardViewHolder) viewHolder) + .setDismissListener( + unused -> { + StorageComponent.get(context) + .unencryptedSharedPrefs() + .edit() + .putBoolean(SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED, true) + .apply(); + setCardAndHeaderPositions(); + notifyDataSetChanged(); + }); + break; case RowType.HEADER_TODAY: ((HeaderViewHolder) viewHolder).setHeader(R.string.new_call_log_header_today); break; @@ -167,17 +227,20 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { break; case RowType.CALL_LOG_ENTRY: NewCallLogViewHolder newCallLogViewHolder = (NewCallLogViewHolder) viewHolder; - int previousHeaders = 0; + int previousCardAndHeaders = 0; + if (duoDisclosureCardPosition != null && position > duoDisclosureCardPosition) { + previousCardAndHeaders++; + } if (todayHeaderPosition != null && position > todayHeaderPosition) { - previousHeaders++; + previousCardAndHeaders++; } if (yesterdayHeaderPosition != null && position > yesterdayHeaderPosition) { - previousHeaders++; + previousCardAndHeaders++; } if (olderHeaderPosition != null && position > olderHeaderPosition) { - previousHeaders++; + previousCardAndHeaders++; } - cursor.moveToPosition(position - previousHeaders); + cursor.moveToPosition(position - previousCardAndHeaders); newCallLogViewHolder.bind(cursor); break; default: @@ -189,6 +252,9 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { @Override @RowType public int getItemViewType(int position) { + if (duoDisclosureCardPosition != null && position == duoDisclosureCardPosition) { + return RowType.DUO_DISCLOSURE_CARD; + } if (todayHeaderPosition != null && position == todayHeaderPosition) { return RowType.HEADER_TODAY; } @@ -203,7 +269,12 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { @Override public int getItemCount() { + int numberOfCards = 0; int numberOfHeaders = 0; + + if (duoDisclosureCardPosition != null) { + numberOfCards++; + } if (todayHeaderPosition != null) { numberOfHeaders++; } @@ -213,7 +284,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { if (olderHeaderPosition != null) { numberOfHeaders++; } - return cursor.getCount() + numberOfHeaders; + return cursor.getCount() + numberOfHeaders + numberOfCards; } static class PopCounts { diff --git a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_duo_disclosure_card.xml b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_duo_disclosure_card.xml new file mode 100644 index 000000000..1e24c8ba2 --- /dev/null +++ b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_duo_disclosure_card.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:background="@color/background_dialer_light"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:paddingStart="16dp" + android:paddingEnd="24dp" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal"> + + <ImageView + android:id="@+id/new_call_log_duo_disclosure_card_logo" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_marginEnd="16dp"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:orientation="vertical"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="12dp" + android:fontFamily="sans-serif-medium" + android:text="@string/new_call_log_duo_disclosure_card_header" + android:textColor="@color/primary_material_dark" + android:textSize="@dimen/call_log_primary_text_size"/> + <TextView + android:id="@+id/new_call_log_duo_disclosure_card_details" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="16dp" + android:lineSpacingExtra="8dp" + android:textColor="@color/primary_material_dark" + android:textSize="14sp"/> + <Button + android:id="@+id/new_call_log_duo_disclosure_card_ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:layout_marginBottom="2dp" + android:layout_gravity="end" + android:paddingLeft="14dp" + android:paddingRight="14dp" + android:text="@string/new_call_log_duo_disclosure_card_ok" + android:textSize="14sp"/> + </LinearLayout> + </LinearLayout> + + <!-- The boundary line at the bottom --> + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginTop="8dp" + android:background="#DBDBDB"/> +</LinearLayout> 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 ebddc3578..f04bffa3f 100644 --- a/java/com/android/dialer/calllog/ui/res/values/strings.xml +++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml @@ -15,7 +15,7 @@ ~ limitations under the License --> -<resources> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Header in call log to group calls from the current day. [CHAR LIMIT=30] --> <string name="new_call_log_header_today">Today</string> @@ -26,4 +26,17 @@ <!-- Header in call log to group calls from before yesterday. [CHAR LIMIT=30] --> <string name="new_call_log_header_older">Older</string> -</resources>
\ No newline at end of file + <!-- Header on the Duo disclosure card. [CHAR_LIMIT=60] --> + <string name="new_call_log_duo_disclosure_card_header"> + Make video calls with Duo + </string> + + <!-- Details on the Duo disclosure card. [CHAR_LIMIT=200] --> + <string name="new_call_log_duo_disclosure_card_details"> + 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> + + <!-- Text on the button on the Duo disclosure card. [CHAR_LIMIT=30] --> + <string name="new_call_log_duo_disclosure_card_ok">OK, got it</string> + +</resources> diff --git a/java/com/android/dialer/duo/Duo.java b/java/com/android/dialer/duo/Duo.java index d2a5491fd..e020c80e6 100644 --- a/java/com/android/dialer/duo/Duo.java +++ b/java/com/android/dialer/duo/Duo.java @@ -18,6 +18,7 @@ package com.android.dialer.duo; import android.content.Context; import android.content.Intent; +import android.support.annotation.DrawableRes; import android.support.annotation.MainThread; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -97,6 +98,11 @@ public interface Duo { @MainThread int getIncomingCallTypeText(); + /** The ID of the drawable resource of a Duo logo. */ + @DrawableRes + @MainThread + int getLogo(); + /** Reachability information for a number. */ @AutoValue abstract class ReachabilityData { diff --git a/java/com/android/dialer/duo/stub/DuoStub.java b/java/com/android/dialer/duo/stub/DuoStub.java index 9e896cfbd..ef78f8b90 100644 --- a/java/com/android/dialer/duo/stub/DuoStub.java +++ b/java/com/android/dialer/duo/stub/DuoStub.java @@ -18,6 +18,7 @@ package com.android.dialer.duo.stub; import android.content.Context; import android.content.Intent; +import android.support.annotation.DrawableRes; import android.support.annotation.MainThread; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -121,4 +122,10 @@ public class DuoStub implements Duo { public int getIncomingCallTypeText() { return -1; } + + @DrawableRes + @Override + public int getLogo() { + return -1; + } } |