diff options
Diffstat (limited to 'java')
21 files changed, 558 insertions, 281 deletions
diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java index 8746b2bf1..e650e77f8 100644 --- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java +++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java @@ -35,6 +35,7 @@ import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule; import com.android.dialer.precall.impl.PreCallModule; import com.android.dialer.preferredsim.PreferredSimModule; import com.android.dialer.preferredsim.suggestion.stub.StubSimSuggestionModule; +import com.android.dialer.promotion.impl.PromotionModule; import com.android.dialer.simulator.impl.SimulatorModule; import com.android.dialer.simulator.stub.StubSimulatorEnrichedCallModule; import com.android.dialer.spam.stub.StubSpamModule; @@ -50,34 +51,34 @@ import javax.inject.Singleton; /** Root component for the AOSP Dialer application. */ @Singleton @Component( - modules = { - ActiveCallsModule.class, - CallLogModule.class, - CallLogConfigModule.class, - CommandLineModule.class, - ContextModule.class, - DialerExecutorModule.class, - GlidePhotoManagerModule.class, - PhoneLookupModule.class, - PhoneNumberGeoUtilModule.class, - PreCallModule.class, - PreferredSimModule.class, - SharedPrefConfigProviderModule.class, - SimulatorModule.class, - StubSimulatorEnrichedCallModule.class, - StorageModule.class, - StubCallLocationModule.class, - StubDuoModule.class, - StubEnrichedCallModule.class, - StubBubbleModule.class, - StubMetricsModule.class, - StubFeedbackModule.class, - StubMapsModule.class, - StubSimSuggestionModule.class, - StubSpamModule.class, - StubSpeakEasyModule.class, - SystemStrictModeModule.class, - VoicemailModule.class, - } -) + modules = { + ActiveCallsModule.class, + CallLogModule.class, + CallLogConfigModule.class, + CommandLineModule.class, + ContextModule.class, + DialerExecutorModule.class, + GlidePhotoManagerModule.class, + PhoneLookupModule.class, + PhoneNumberGeoUtilModule.class, + PreCallModule.class, + PreferredSimModule.class, + PromotionModule.class, + SharedPrefConfigProviderModule.class, + SimulatorModule.class, + StubSimulatorEnrichedCallModule.class, + StorageModule.class, + StubCallLocationModule.class, + StubDuoModule.class, + StubEnrichedCallModule.class, + StubBubbleModule.class, + StubMetricsModule.class, + StubFeedbackModule.class, + StubMapsModule.class, + StubSimSuggestionModule.class, + StubSpamModule.class, + StubSpeakEasyModule.class, + SystemStrictModeModule.class, + VoicemailModule.class, + }) public interface AospDialerRootComponent extends BaseDialerRootComponent {} diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java index cad2eb7e0..1d346accf 100644 --- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java +++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java @@ -36,6 +36,7 @@ import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent; import com.android.dialer.precall.PreCallComponent; import com.android.dialer.preferredsim.PreferredSimComponent; import com.android.dialer.preferredsim.suggestion.SimSuggestionComponent; +import com.android.dialer.promotion.PromotionComponent; import com.android.dialer.simulator.SimulatorComponent; import com.android.dialer.spam.SpamComponent; import com.android.dialer.speeddial.loader.UiItemLoaderComponent; @@ -72,6 +73,7 @@ public interface BaseDialerRootComponent PhoneNumberGeoUtilComponent.HasComponent, PreCallComponent.HasComponent, PreferredSimComponent.HasComponent, + PromotionComponent.HasComponent, UiItemLoaderComponent.HasComponent, SimSuggestionComponent.HasComponent, SimulatorComponent.HasComponent, diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java index 62b8ca251..8c0ac56a2 100644 --- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java +++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java @@ -35,6 +35,7 @@ import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule; import com.android.dialer.precall.impl.PreCallModule; import com.android.dialer.preferredsim.PreferredSimModule; import com.android.dialer.preferredsim.suggestion.stub.StubSimSuggestionModule; +import com.android.dialer.promotion.impl.PromotionModule; import com.android.dialer.simulator.impl.SimulatorModule; import com.android.dialer.simulator.stub.StubSimulatorEnrichedCallModule; import com.android.dialer.spam.stub.StubSpamModule; @@ -53,34 +54,34 @@ import javax.inject.Singleton; */ @Singleton @Component( - modules = { - ActiveCallsModule.class, - CallLocationModule.class, - CallLogModule.class, - CallLogConfigModule.class, - CommandLineModule.class, - ContextModule.class, - DialerExecutorModule.class, - GlidePhotoManagerModule.class, - MapsModule.class, - PhoneLookupModule.class, // TODO(zachh): Module which uses APDL? - PhoneNumberGeoUtilModule.class, - PreCallModule.class, - PreferredSimModule.class, - SharedPrefConfigProviderModule.class, - SimulatorModule.class, - StorageModule.class, - StubSimulatorEnrichedCallModule.class, - StubDuoModule.class, - StubEnrichedCallModule.class, - StubFeedbackModule.class, - StubMetricsModule.class, - StubBubbleModule.class, - StubSimSuggestionModule.class, - StubSpamModule.class, - StubSpeakEasyModule.class, - SystemStrictModeModule.class, - VoicemailModule.class, - } -) + modules = { + ActiveCallsModule.class, + CallLocationModule.class, + CallLogModule.class, + CallLogConfigModule.class, + CommandLineModule.class, + ContextModule.class, + DialerExecutorModule.class, + GlidePhotoManagerModule.class, + MapsModule.class, + PhoneLookupModule.class, // TODO(zachh): Module which uses APDL? + PhoneNumberGeoUtilModule.class, + PreCallModule.class, + PreferredSimModule.class, + PromotionModule.class, + SharedPrefConfigProviderModule.class, + SimulatorModule.class, + StorageModule.class, + StubSimulatorEnrichedCallModule.class, + StubDuoModule.class, + StubEnrichedCallModule.class, + StubFeedbackModule.class, + StubMetricsModule.class, + StubBubbleModule.class, + StubSimSuggestionModule.class, + StubSpamModule.class, + StubSpeakEasyModule.class, + SystemStrictModeModule.class, + VoicemailModule.class, + }) public interface GoogleStubDialerRootComponent extends BaseDialerRootComponent {} diff --git a/java/com/android/dialer/calllog/ui/DuoDisclosureCardViewHolder.java b/java/com/android/dialer/calllog/ui/DuoDisclosureCardViewHolder.java deleted file mode 100644 index 6b9112789..000000000 --- a/java/com/android/dialer/calllog/ui/DuoDisclosureCardViewHolder.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 501cf1657..58bf8c061 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java @@ -17,11 +17,9 @@ package com.android.dialer.calllog.ui; import android.app.Activity; 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; @@ -29,37 +27,27 @@ import android.view.ViewGroup; import com.android.dialer.calllog.database.Coalescer; 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.promotion.RttPromotion; -import com.android.dialer.storage.StorageComponent; +import com.android.dialer.promotion.Promotion; import com.android.dialer.time.Clock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.concurrent.TimeUnit; /** {@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"; - - private static final String SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS = - "duo_disclosure_first_viewed_time_ms"; - /** IntDef for the different types of rows that can be shown in the call log. */ @Retention(RetentionPolicy.SOURCE) @IntDef({ - RowType.DUO_DISCLOSURE_CARD, + RowType.PROMOTION_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; + /** The promotion card. */ + int PROMOTION_CARD = 1; /** Header that displays "Today". */ int HEADER_TODAY = 2; @@ -78,14 +66,12 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { private final Activity activity; private final RealtimeRowProcessor realtimeRowProcessor; private final PopCounts popCounts = new PopCounts(); - private final SharedPreferences sharedPref; - private final OnScrollListenerForRecordingDuoDisclosureFirstViewTime - onScrollListenerForRecordingDuoDisclosureFirstViewTime; + @Nullable private final Promotion promotion; private Cursor cursor; - /** Position of the Duo disclosure card. Null when it should not be displayed. */ - @Nullable private Integer duoDisclosureCardPosition; + /** Position of the promotion card. Null when it should not be displayed. */ + @Nullable private Integer promotionCardPosition; /** Position of the "Today" header. Null when it should not be displayed. */ @Nullable private Integer todayHeaderPosition; @@ -96,14 +82,12 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { /** Position of the "Older" header. Null when it should not be displayed. */ @Nullable private Integer olderHeaderPosition; - NewCallLogAdapter(Activity activity, Cursor cursor, Clock clock) { + NewCallLogAdapter(Activity activity, Cursor cursor, Clock clock, @Nullable Promotion promotion) { this.activity = activity; this.cursor = cursor; this.clock = clock; this.realtimeRowProcessor = CallLogUiComponent.get(activity).realtimeRowProcessor(); - this.sharedPref = StorageComponent.get(activity).unencryptedSharedPrefs(); - this.onScrollListenerForRecordingDuoDisclosureFirstViewTime = - new OnScrollListenerForRecordingDuoDisclosureFirstViewTime(sharedPref, clock); + this.promotion = promotion; setCardAndHeaderPositions(); } @@ -126,11 +110,11 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { } private void setCardAndHeaderPositions() { - // Set the position for the Duo disclosure card if it should be shown. - duoDisclosureCardPosition = null; + // Set the position for the promotion card if it should be shown. + promotionCardPosition = null; int numCards = 0; - if (shouldShowDuoDisclosureCard()) { - duoDisclosureCardPosition = 0; + if (promotion != null && promotion.isEligibleToBeShown()) { + promotionCardPosition = 0; numCards++; } @@ -174,61 +158,26 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { !cursor.isAfterLast() ? numItemsInToday + numItemsInYesterday + numCards : null; } - private boolean shouldShowDuoDisclosureCard() { - if (new RttPromotion(activity).shouldShow()) { - return false; - } - // Don't show the Duo disclosure card if - // (1) Duo integration is not enabled on the device, or - // (2) Duo is not activated. - Duo duo = DuoComponent.get(activity).getDuo(); - if (!duo.isEnabled(activity) || !duo.isActivated(activity)) { - return false; - } - - // Don't show the Duo disclosure card if it has been dismissed. - if (sharedPref.getBoolean(SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED, false)) { - return false; - } - - // At this point, Duo is activated and the disclosure card hasn't been dismissed. - // We should show the card if it has never been viewed by the user. - if (!sharedPref.contains(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS)) { - return true; - } - - // At this point, the card has been viewed but not dismissed. - // We should not show the card if it has been viewed for more than 1 day. - long duoDisclosureFirstViewTimeMillis = - sharedPref.getLong(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS, 0); - return clock.currentTimeMillis() - duoDisclosureFirstViewTimeMillis - <= TimeUnit.DAYS.toMillis(1); - } - @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); - // Register a OnScrollListener that records the timestamp at which the Duo disclosure is first - // viewed if - // (1) the Duo disclosure card should be shown, and - // (2) it hasn't been viewed yet. - if (shouldShowDuoDisclosureCard() - && !sharedPref.contains(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS)) { - recyclerView.addOnScrollListener(onScrollListenerForRecordingDuoDisclosureFirstViewTime); + // Register a OnScrollListener that records when the promotion is viewed. + if (promotion != null && promotion.isEligibleToBeShown()) { + recyclerView.addOnScrollListener( + new OnScrollListenerForRecordingPromotionCardFirstViewTime(promotion)); } } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType) { switch (viewType) { - case RowType.DUO_DISCLOSURE_CARD: - return new DuoDisclosureCardViewHolder( + case RowType.PROMOTION_CARD: + return new PromotionCardViewHolder( LayoutInflater.from(activity) .inflate( - R.layout.new_call_log_duo_disclosure_card, - viewGroup, - /* attachToRoot = */ false)); + R.layout.new_call_log_promotion_card, viewGroup, /* attachToRoot = */ false), + promotion); case RowType.HEADER_TODAY: case RowType.HEADER_YESTERDAY: case RowType.HEADER_OLDER: @@ -252,16 +201,11 @@ 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) + case RowType.PROMOTION_CARD: + ((PromotionCardViewHolder) viewHolder) .setDismissListener( - unused -> { - StorageComponent.get(activity) - .unencryptedSharedPrefs() - .edit() - .putBoolean(SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED, true) - .apply(); - notifyItemRemoved(duoDisclosureCardPosition); + () -> { + notifyItemRemoved(promotionCardPosition); setCardAndHeaderPositions(); }); break; @@ -277,7 +221,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { case RowType.CALL_LOG_ENTRY: NewCallLogViewHolder newCallLogViewHolder = (NewCallLogViewHolder) viewHolder; int previousCardAndHeaders = 0; - if (duoDisclosureCardPosition != null && position > duoDisclosureCardPosition) { + if (promotionCardPosition != null && position > promotionCardPosition) { previousCardAndHeaders++; } if (todayHeaderPosition != null && position > todayHeaderPosition) { @@ -301,8 +245,8 @@ 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 (promotionCardPosition != null && position == promotionCardPosition) { + return RowType.PROMOTION_CARD; } if (todayHeaderPosition != null && position == todayHeaderPosition) { return RowType.HEADER_TODAY; @@ -321,7 +265,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { int numberOfCards = 0; int numberOfHeaders = 0; - if (duoDisclosureCardPosition != null) { + if (promotionCardPosition != null) { numberOfCards++; } if (todayHeaderPosition != null) { @@ -337,35 +281,27 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { } /** - * A {@link RecyclerView.OnScrollListener} that records the timestamp at which the Duo disclosure - * card is first viewed. + * A {@link RecyclerView.OnScrollListener} that records the timestamp at which the promotion card + * is first viewed. * * <p>We consider the card as viewed if the user scrolls the containing RecyclerView since such * action is a strong proof. */ - private static final class OnScrollListenerForRecordingDuoDisclosureFirstViewTime + private static final class OnScrollListenerForRecordingPromotionCardFirstViewTime extends RecyclerView.OnScrollListener { - private final SharedPreferences sharedPref; - private final Clock clock; + private final Promotion promotion; - OnScrollListenerForRecordingDuoDisclosureFirstViewTime( - SharedPreferences sharedPref, Clock clock) { - this.sharedPref = sharedPref; - this.clock = clock; + OnScrollListenerForRecordingPromotionCardFirstViewTime(Promotion promotion) { + this.promotion = promotion; } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - if (!sharedPref.contains(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS) - && newState == RecyclerView.SCROLL_STATE_SETTLING) { - sharedPref - .edit() - .putLong( - SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS, clock.currentTimeMillis()) - .apply(); - - // Recording the timestamp is this listener's sole responsibility. + if (newState == RecyclerView.SCROLL_STATE_SETTLING) { + promotion.onViewed(); + + // Recording promotion is viewed is this listener's sole responsibility. // We can remove it from the containing RecyclerView after the job is done. recyclerView.removeOnScrollListener(this); } diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java index 2feed4068..ec6e8a0fd 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java @@ -42,6 +42,8 @@ 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.promotion.Promotion.PromotionType; +import com.android.dialer.promotion.PromotionComponent; import com.android.dialer.util.PermissionsUtil; import com.android.dialer.widget.EmptyContentView; import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; @@ -289,6 +291,7 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback return new AnnotatedCallLogCursorLoader(Assert.isNotNull(getContext())); } + @SuppressWarnings("AndroidApiChecker") // Use of optional @Override public void onLoadFinished(Loader<Cursor> loader, Cursor newCursor) { LogUtil.enterBlock("NewCallLogFragment.onLoadFinished"); @@ -319,7 +322,14 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback // instead. Activity activity = Assert.isNotNull(getActivity()); recyclerView.setAdapter( - new NewCallLogAdapter(activity, coalescedCursor, System::currentTimeMillis)); + new NewCallLogAdapter( + activity, + coalescedCursor, + System::currentTimeMillis, + PromotionComponent.get(getContext()) + .promotionManager() + .getHighestPriorityPromotion(PromotionType.CARD) + .orElse(null))); } else { ((NewCallLogAdapter) recyclerView.getAdapter()).updateCursor(coalescedCursor); } diff --git a/java/com/android/dialer/calllog/ui/PromotionCardViewHolder.java b/java/com/android/dialer/calllog/ui/PromotionCardViewHolder.java new file mode 100644 index 000000000..c7d62ba16 --- /dev/null +++ b/java/com/android/dialer/calllog/ui/PromotionCardViewHolder.java @@ -0,0 +1,63 @@ +/* + * 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.support.v7.widget.RecyclerView.ViewHolder; +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.dialer.promotion.Promotion; + +/** ViewHolder for {@link NewCallLogAdapter} to display the Duo disclosure card. */ +public class PromotionCardViewHolder extends ViewHolder { + + /** Listener to be called when promotion card is dismissed. */ + interface DismissListener { + void onDismiss(); + } + + private final Button okButton; + private final Promotion promotion; + + PromotionCardViewHolder(View itemView, Promotion promotion) { + super(itemView); + this.promotion = promotion; + + ImageView iconView = itemView.findViewById(R.id.new_call_log_promotion_card_icon); + iconView.setImageResource(promotion.getIconRes()); + + TextView cardTitleView = itemView.findViewById(R.id.new_call_log_promotion_card_title); + cardTitleView.setText(promotion.getTitle()); + + TextView cardDetailsView = itemView.findViewById(R.id.new_call_log_promotion_card_details); + cardDetailsView.setText(promotion.getDetails()); + 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_promotion_card_ok); + } + + void setDismissListener(DismissListener listener) { + okButton.setOnClickListener( + v -> { + promotion.dismiss(); + listener.onDismiss(); + }); + } +} 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_promotion_card.xml index 93fd0ac40..0e6d551fb 100644 --- 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_promotion_card.xml @@ -18,8 +18,8 @@ <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="?android:attr/colorBackground"> + android:background="?android:attr/colorBackground" + android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" @@ -32,7 +32,7 @@ android:orientation="horizontal"> <ImageView - android:id="@+id/new_call_log_duo_disclosure_card_logo" + android:id="@+id/new_call_log_promotion_card_icon" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginEnd="16dp" @@ -45,15 +45,15 @@ android:orientation="vertical"> <TextView + android:id="@+id/new_call_log_promotion_card_title" 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:id="@+id/new_call_log_promotion_card_details" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" @@ -61,7 +61,7 @@ android:textColor="@color/primary_material_dark" android:textSize="14sp"/> <Button - android:id="@+id/new_call_log_duo_disclosure_card_ok" + android:id="@+id/new_call_log_promotion_card_ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" 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 e78b227ab..3888eb90d 100644 --- a/java/com/android/dialer/calllog/ui/res/values/strings.xml +++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml @@ -32,17 +32,6 @@ <!-- Header in call log to group calls from before yesterday. [CHAR LIMIT=30] --> <string name="new_call_log_header_older">Older</string> - - <!-- 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> - <!-- 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> diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java index 16f46c10f..402edb3d5 100644 --- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java +++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java @@ -109,7 +109,8 @@ import com.android.dialer.metrics.MetricsComponent; import com.android.dialer.postcall.PostCall; import com.android.dialer.precall.PreCall; import com.android.dialer.promotion.Promotion; -import com.android.dialer.promotion.RttPromotion; +import com.android.dialer.promotion.Promotion.PromotionType; +import com.android.dialer.promotion.PromotionComponent; import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener; import com.android.dialer.smartdial.util.SmartDialPrefix; import com.android.dialer.speeddial.SpeedDialFragment; @@ -128,6 +129,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.Locale; +import java.util.Optional; import java.util.concurrent.TimeUnit; /** @@ -1326,15 +1328,19 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen showPromotionBottomSheet(activity, bottomSheet); } + @SuppressWarnings("AndroidApiChecker") // Use of optional private static void showPromotionBottomSheet(Context context, View view) { - // TODO(a bug): Use a promotion manager to get promotion to show. - Promotion promotion = new RttPromotion(context); BottomSheetBehavior<View> bottomSheetBehavior = BottomSheetBehavior.from(view); - - if (!promotion.shouldShow()) { + Optional<Promotion> promotionOptional = + PromotionComponent.get(context) + .promotionManager() + .getHighestPriorityPromotion(PromotionType.BOTTOM_SHEET); + if (!promotionOptional.isPresent()) { bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); return; } + + Promotion promotion = promotionOptional.get(); ImageView icon = view.findViewById(R.id.promotion_icon); icon.setImageResource(promotion.getIconRes()); TextView details = view.findViewById(R.id.promotion_details); diff --git a/java/com/android/dialer/main/impl/res/layout/promotion_bottom_sheet.xml b/java/com/android/dialer/main/impl/res/layout/promotion_bottom_sheet.xml index c7f2d9a01..709de52b8 100644 --- a/java/com/android/dialer/main/impl/res/layout/promotion_bottom_sheet.xml +++ b/java/com/android/dialer/main/impl/res/layout/promotion_bottom_sheet.xml @@ -62,7 +62,6 @@ android:textSize="14sp"/> <Button android:id="@+id/ok_got_it" - style="@style/Widget.AppCompat.Button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" @@ -70,7 +69,6 @@ android:layout_gravity="end" android:paddingStart="16dp" android:paddingEnd="16dp" - android:backgroundTint="?android:attr/colorPrimary" android:fontFamily="sans-serif-medium" android:stateListAnimator="@null" android:text="@string/ok_got_it" diff --git a/java/com/android/dialer/promotion/Promotion.java b/java/com/android/dialer/promotion/Promotion.java index 3cd16d4a6..176606ff4 100644 --- a/java/com/android/dialer/promotion/Promotion.java +++ b/java/com/android/dialer/promotion/Promotion.java @@ -17,23 +17,51 @@ package com.android.dialer.promotion; import android.support.annotation.DrawableRes; +import android.support.annotation.IntDef; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** Interface for promotion bottom sheet. */ public interface Promotion { - /** Returns if this promotion should be shown. */ - boolean shouldShow(); + /** + * Type of promotion, which means promotion should be shown as a card in {@link + * android.support.v7.widget.RecyclerView} or {@link + * android.support.design.bottomsheet.BottomSheetBehavior}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({PromotionType.CARD, PromotionType.BOTTOM_SHEET}) + @interface PromotionType { + /** Shown as card in call log or voicemail tab. */ + int CARD = 1; - /** Sets to show this promotion. */ - void setShouldShow(boolean shouldShow); + /** Shown as bottom sheet. */ + int BOTTOM_SHEET = 2; + } + + /** Returns {@link PromotionType} for this promotion. */ + @PromotionType + int getType(); + + /** + * Returns if this promotion should be shown. This usually means the promotion is enabled and not + * dismissed yet. + */ + boolean isEligibleToBeShown(); + + /** Called when this promotion is first time viewed by user. */ + default void onViewed() {} /** Dismisses this promotion. This is called when user acknowledged the promotion. */ void dismiss(); + /** Returns title text of the promotion. */ CharSequence getTitle(); + /** Returns details text of the promotion. */ CharSequence getDetails(); + /** Returns resource id of the icon for the promotion. */ @DrawableRes int getIconRes(); } diff --git a/java/com/android/dialer/promotion/PromotionComponent.java b/java/com/android/dialer/promotion/PromotionComponent.java new file mode 100644 index 000000000..caf10dbb0 --- /dev/null +++ b/java/com/android/dialer/promotion/PromotionComponent.java @@ -0,0 +1,43 @@ +/* + * 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.promotion; + +import android.content.Context; +import com.android.dialer.inject.HasRootComponent; +import com.android.dialer.inject.IncludeInDialerRoot; +import com.google.common.collect.ImmutableList; +import dagger.Subcomponent; + +/** Component for promotion. */ +@Subcomponent +public abstract class PromotionComponent { + + public abstract PromotionManager promotionManager(); + + public abstract ImmutableList<Promotion> priorityPromotionList(); + + public static PromotionComponent get(Context context) { + return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) + .promotionComponent(); + } + + /** Used to refer to the root application component. */ + @IncludeInDialerRoot + public interface HasComponent { + PromotionComponent promotionComponent(); + } +} diff --git a/java/com/android/dialer/promotion/PromotionManager.java b/java/com/android/dialer/promotion/PromotionManager.java new file mode 100644 index 000000000..a86a745ad --- /dev/null +++ b/java/com/android/dialer/promotion/PromotionManager.java @@ -0,0 +1,67 @@ +/* + * 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.promotion; + +import com.android.dialer.promotion.Promotion.PromotionType; +import com.google.common.collect.ImmutableList; +import java.util.Optional; +import javax.inject.Inject; + +/** + * A class to manage all promotion cards/bottom sheet. + * + * <p>Only one promotion with highest priority will be shown at a time no matter type. So if there + * are one card and one bottom sheet promotion, either one will be shown instead of both. + */ +public final class PromotionManager { + + /** Promotion priority order list. Promotions with higher priority must be added first. */ + private ImmutableList<Promotion> priorityPromotionList; + + @Inject + public PromotionManager(ImmutableList<Promotion> priorityPromotionList) { + this.priorityPromotionList = priorityPromotionList; + } + + /** + * Returns promotion should show with highest priority. {@link Optional#empty()} if no promotion + * should be shown with given {@link PromotionType}. + * + * <p>e.g. if FooPromotion(card, high priority) and BarPromotion(bottom sheet, low priority) are + * both enabled, getHighestPriorityPromotion(CARD) returns Optional.of(FooPromotion) but + * getHighestPriorityPromotion(BOTTOM_SHEET) returns {@link Optional#empty()}. + * + * <p>Currently it only supports promotion in call log tab. + * + * <p>TODO(wangqi): add support for other tabs. + */ + @SuppressWarnings("AndroidApiChecker") // Use of optional + public Optional<Promotion> getHighestPriorityPromotion(@PromotionType int type) { + for (Promotion promotion : priorityPromotionList) { + if (promotion.isEligibleToBeShown()) { + if (promotion.getType() == type) { + return Optional.of(promotion); + } else { + // Returns empty promotion since it's not the type looking for and only one promotion + // should be shown at a time. + return Optional.empty(); + } + } + } + return Optional.empty(); + } +} diff --git a/java/com/android/dialer/promotion/AndroidManifest.xml b/java/com/android/dialer/promotion/impl/AndroidManifest.xml index bd85b104f..c938b9a37 100644 --- a/java/com/android/dialer/promotion/AndroidManifest.xml +++ b/java/com/android/dialer/promotion/impl/AndroidManifest.xml @@ -13,4 +13,11 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<manifest package="com.android.dialer.promotion"/> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.dialer.promotion"> + + <uses-sdk + android:minSdkVersion="24" + android:targetSdkVersion="28"/> + +</manifest> diff --git a/java/com/android/dialer/promotion/impl/DuoPromotion.java b/java/com/android/dialer/promotion/impl/DuoPromotion.java new file mode 100644 index 000000000..750e4a196 --- /dev/null +++ b/java/com/android/dialer/promotion/impl/DuoPromotion.java @@ -0,0 +1,132 @@ +/* + * 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.promotion.impl; + +import android.content.Context; +import android.content.SharedPreferences; +import android.support.annotation.VisibleForTesting; +import com.android.dialer.configprovider.ConfigProvider; +import com.android.dialer.duo.Duo; +import com.android.dialer.inject.ApplicationContext; +import com.android.dialer.promotion.Promotion; +import com.android.dialer.spannable.ContentWithLearnMoreSpanner; +import com.android.dialer.storage.Unencrypted; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; + +/** Duo promotion. */ +final class DuoPromotion implements Promotion { + private static final String SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED = "duo_disclosure_dismissed"; + + private static final String SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS = + "duo_disclosure_first_viewed_time_ms"; + @VisibleForTesting static final String FLAG_SHOW_DUO_DISCLOSURE = "show_duo_disclosure"; + + @VisibleForTesting + static final String FLAG_DUO_DISCLOSURE_AUTO_DISMISS_AFTER_VIEWED_TIME_MILLIS = + "show_duo_disclosure_auto_dismiss_after_viewed_time_millis"; + + private final Context appContext; + private final ConfigProvider configProvider; + private final Duo duo; + private final SharedPreferences sharedPreferences; + + @Inject + DuoPromotion( + @ApplicationContext Context context, + ConfigProvider configProvider, + Duo duo, + @Unencrypted SharedPreferences sharedPreferences) { + this.appContext = context; + this.configProvider = configProvider; + this.duo = duo; + this.sharedPreferences = sharedPreferences; + } + + @Override + public int getType() { + return PromotionType.CARD; + } + + @Override + public boolean isEligibleToBeShown() { + if (!configProvider.getBoolean(FLAG_SHOW_DUO_DISCLOSURE, false)) { + return false; + } + // Don't show the Duo disclosure card if + // (1) Duo integration is not enabled on the device, or + // (2) Duo is not activated. + if (!duo.isEnabled(appContext) || !duo.isActivated(appContext)) { + return false; + } + + // Don't show the Duo disclosure card if it has been dismissed. + if (sharedPreferences.getBoolean(SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED, false)) { + return false; + } + + // At this point, Duo is activated and the disclosure card hasn't been dismissed. + // We should show the card if it has never been viewed by the user. + if (!sharedPreferences.contains(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS)) { + return true; + } + + // At this point, the card has been viewed but not dismissed. + // We should not show the card if it has been viewed for more than 1 day. + long duoDisclosureFirstViewTimeMillis = + sharedPreferences.getLong(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS, 0); + return System.currentTimeMillis() - duoDisclosureFirstViewTimeMillis + <= configProvider.getLong( + FLAG_DUO_DISCLOSURE_AUTO_DISMISS_AFTER_VIEWED_TIME_MILLIS, TimeUnit.DAYS.toMillis(1)); + } + + @Override + public void onViewed() { + if (!sharedPreferences.contains(SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS)) { + sharedPreferences + .edit() + .putLong( + SHARED_PREF_KEY_DUO_DISCLOSURE_FIRST_VIEW_TIME_MILLIS, System.currentTimeMillis()) + .apply(); + } + } + + @Override + public void dismiss() { + sharedPreferences.edit().putBoolean(SHARED_PREF_KEY_DUO_DISCLOSURE_DISMISSED, true).apply(); + } + + @Override + public CharSequence getTitle() { + return appContext.getString(R.string.duo_disclosure_title); + } + + @Override + public CharSequence getDetails() { + return new ContentWithLearnMoreSpanner(appContext) + .create( + appContext.getString(R.string.duo_disclosure_details), + configProvider.getString( + "duo_disclosure_link_full_url", + "http://support.google.com/pixelphone/?p=dialer_duo")); + } + + @Override + public int getIconRes() { + return duo.getLogo(); + } +} diff --git a/java/com/android/dialer/promotion/impl/PromotionModule.java b/java/com/android/dialer/promotion/impl/PromotionModule.java new file mode 100644 index 000000000..f0908780c --- /dev/null +++ b/java/com/android/dialer/promotion/impl/PromotionModule.java @@ -0,0 +1,36 @@ +/* + * 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.promotion.impl; + +import com.android.dialer.inject.DialerVariant; +import com.android.dialer.inject.InstallIn; +import com.android.dialer.promotion.Promotion; +import com.google.common.collect.ImmutableList; +import dagger.Module; +import dagger.Provides; + +/** Module for Promotion. */ +@InstallIn(variants = {DialerVariant.DIALER_TEST}) +@Module +public abstract class PromotionModule { + + @Provides + static ImmutableList<Promotion> providePriorityPromotionList( + RttPromotion rttPromotion, DuoPromotion duoPromotion) { + return ImmutableList.of(rttPromotion, duoPromotion); + } +} diff --git a/java/com/android/dialer/promotion/RttPromotion.java b/java/com/android/dialer/promotion/impl/RttPromotion.java index feb6e4734..f0f7f546b 100644 --- a/java/com/android/dialer/promotion/RttPromotion.java +++ b/java/com/android/dialer/promotion/impl/RttPromotion.java @@ -14,29 +14,45 @@ * limitations under the License */ -package com.android.dialer.promotion; +package com.android.dialer.promotion.impl; import android.content.Context; import android.content.SharedPreferences; import android.support.annotation.DrawableRes; import com.android.dialer.common.LogUtil; -import com.android.dialer.configprovider.ConfigProviderBindings; +import com.android.dialer.configprovider.ConfigProvider; +import com.android.dialer.inject.ApplicationContext; +import com.android.dialer.promotion.Promotion; import com.android.dialer.spannable.ContentWithLearnMoreSpanner; import com.android.dialer.storage.StorageComponent; +import com.android.dialer.storage.Unencrypted; +import javax.inject.Inject; /** RTT promotion. */ public final class RttPromotion implements Promotion { private static final String SHARED_PREFERENCE_KEY_ENABLED = "rtt_promotion_enabled"; private static final String SHARED_PREFERENCE_KEY_DISMISSED = "rtt_promotion_dismissed"; private final Context appContext; + private final SharedPreferences sharedPreferences; + private final ConfigProvider configProvider; - public RttPromotion(Context context) { - appContext = context.getApplicationContext(); + @Override + public int getType() { + return PromotionType.BOTTOM_SHEET; + } + + @Inject + RttPromotion( + @ApplicationContext Context context, + @Unencrypted SharedPreferences sharedPreferences, + ConfigProvider configProvider) { + appContext = context; + this.sharedPreferences = sharedPreferences; + this.configProvider = configProvider; } @Override - public boolean shouldShow() { - SharedPreferences sharedPreferences = StorageComponent.get(appContext).unencryptedSharedPrefs(); + public boolean isEligibleToBeShown() { return sharedPreferences.getBoolean(SHARED_PREFERENCE_KEY_ENABLED, false) && !sharedPreferences.getBoolean(SHARED_PREFERENCE_KEY_DISMISSED, false); } @@ -51,10 +67,9 @@ public final class RttPromotion implements Promotion { return new ContentWithLearnMoreSpanner(appContext) .create( appContext.getString(R.string.rtt_promotion_details), - ConfigProviderBindings.get(appContext) - .getString( - "rtt_promo_learn_more_link_full_url", - "http://support.google.com/pixelphone/?p=dialer_rtt")); + configProvider.getString( + "rtt_promo_learn_more_link_full_url", + "http://support.google.com/pixelphone/?p=dialer_rtt")); } @Override @@ -63,22 +78,17 @@ public final class RttPromotion implements Promotion { return R.drawable.quantum_ic_rtt_vd_theme_24; } - @Override - public void setShouldShow(boolean shouldShow) { - LogUtil.i("RttPromotion.setShouldShow", "shouldShow: %b", shouldShow); - StorageComponent.get(appContext) + public static void setEnabled(Context context) { + LogUtil.enterBlock("RttPromotion.setEnabled"); + StorageComponent.get(context) .unencryptedSharedPrefs() .edit() - .putBoolean(SHARED_PREFERENCE_KEY_ENABLED, shouldShow) + .putBoolean(SHARED_PREFERENCE_KEY_ENABLED, true) .apply(); } @Override public void dismiss() { - StorageComponent.get(appContext) - .unencryptedSharedPrefs() - .edit() - .putBoolean(SHARED_PREFERENCE_KEY_DISMISSED, true) - .apply(); + sharedPreferences.edit().putBoolean(SHARED_PREFERENCE_KEY_DISMISSED, true).apply(); } } diff --git a/java/com/android/dialer/promotion/res/values/strings.xml b/java/com/android/dialer/promotion/impl/res/values/strings.xml index 633671546..899074932 100644 --- a/java/com/android/dialer/promotion/res/values/strings.xml +++ b/java/com/android/dialer/promotion/impl/res/values/strings.xml @@ -23,4 +23,13 @@ disability, or need more than voice alone. RTT messaging transcripts are stored on your device in the call history. <xliff:g exmaple="Learn More">%1$s</xliff:g></string> + <!-- Header on the Duo disclosure card. [CHAR_LIMIT=60] --> + <string name="duo_disclosure_title"> + Make video calls with Duo + </string> + + <!-- Details on the Duo disclosure card. [CHAR_LIMIT=200] --> + <string name="duo_disclosure_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> </resources> diff --git a/java/com/android/dialer/theme/res/values/theme_dialer_light.xml b/java/com/android/dialer/theme/res/values/theme_dialer_light.xml index 728842915..ab4ae936d 100644 --- a/java/com/android/dialer/theme/res/values/theme_dialer_light.xml +++ b/java/com/android/dialer/theme/res/values/theme_dialer_light.xml @@ -60,8 +60,6 @@ <!-- Should be kept in sync with the theme above (minus anything related to actionbars) --> <style name="Dialer.ThemeBase.NoActionBar" parent="@style/Theme.AppCompat.Light.NoActionBar"> - <item name="android:textAppearanceButton">@style/DialerButtonTextStyle</item> - <!-- These values should be used to color all backgrounds. --> <item name="android:colorBackground">@color/dialer_background_light</item> <item name="android:colorBackgroundFloating">@color/dialer_background_floating_light</item> @@ -72,6 +70,7 @@ <item name="android:textColorPrimaryInverse">@color/dialer_primary_text_color_inverse</item> <item name="android:textColorSecondaryInverse">@color/dialer_secondary_text_color_inverse</item> <item name="android:textColorHint">@color/dialer_text_hint_color</item> + <item name="android:textColorLink">@color/dialer_theme_color</item> <!-- These will be automatically used to color most Appcompat/Material widgets. --> <item name="android:colorPrimary">@color/dialer_theme_color</item> @@ -81,6 +80,10 @@ <item name="android:colorAccent">@color/dialer_secondary_color</item> <item name="colorAccent">@color/dialer_secondary_color</item> + <!-- Used for material buttons and widgets --> + <item name="android:colorButtonNormal">@color/dialer_theme_color</item> + <item name="android:textAppearanceButton">@style/DialerButtonTextStyle</item> + <!-- Used to automatically style check/selected checkbox, switches and radio buttons --> <item name="colorControlActivated">?android:attr/colorPrimary</item> diff --git a/java/com/android/incallui/call/CallList.java b/java/com/android/incallui/call/CallList.java index 6940f7d6c..634a302a2 100644 --- a/java/com/android/incallui/call/CallList.java +++ b/java/com/android/incallui/call/CallList.java @@ -37,7 +37,7 @@ import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.metrics.Metrics; import com.android.dialer.metrics.MetricsComponent; -import com.android.dialer.promotion.RttPromotion; +import com.android.dialer.promotion.impl.RttPromotion; import com.android.dialer.shortcuts.ShortcutUsageReporter; import com.android.dialer.spam.SpamComponent; import com.android.dialer.spam.status.SpamStatus; @@ -210,7 +210,7 @@ public class CallList implements DialerCallDelegate { || call.getState() == DialerCallState.CALL_WAITING) { if (call.isActiveRttCall()) { if (!call.isPhoneAccountRttCapable()) { - new RttPromotion(context).setShouldShow(true); + RttPromotion.setEnabled(context); } Logger.get(context) .logCallImpression( |