summaryrefslogtreecommitdiff
path: root/java/com/android/incallui/answer/impl
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/incallui/answer/impl')
-rw-r--r--java/com/android/incallui/answer/impl/AnswerFragment.java78
-rw-r--r--java/com/android/incallui/answer/impl/AnswerVideoCallScreen.java19
-rw-r--r--java/com/android/incallui/answer/impl/affordance/SwipeButtonHelper.java2
-rw-r--r--java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java2
-rw-r--r--java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java15
-rw-r--r--java/com/android/incallui/answer/impl/hint/AndroidManifest.xml2
-rw-r--r--java/com/android/incallui/answer/impl/hint/AnswerHintFactory.java13
-rw-r--r--java/com/android/incallui/answer/impl/hint/EventPayloadLoaderImpl.java118
-rw-r--r--java/com/android/incallui/answer/impl/hint/PawAnswerHint.java (renamed from java/com/android/incallui/answer/impl/hint/EventAnswerHint.java)17
-rw-r--r--java/com/android/incallui/answer/impl/hint/PawImageLoader.java (renamed from java/com/android/incallui/answer/impl/hint/EventPayloadLoader.java)8
-rw-r--r--java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java48
-rw-r--r--java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java (renamed from java/com/android/incallui/answer/impl/hint/EventSecretCodeListener.java)38
-rw-r--r--java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/cat_paw.webpbin0 -> 68172 bytes
-rw-r--r--java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/dog_paw.webpbin0 -> 22704 bytes
-rw-r--r--java/com/android/incallui/answer/impl/hint/res/layout/paw_hint.xml (renamed from java/com/android/incallui/answer/impl/hint/res/layout/event_hint.xml)7
-rw-r--r--java/com/android/incallui/answer/impl/proguard.flags5
-rw-r--r--java/com/android/incallui/answer/impl/res/values/dimens.xml1
17 files changed, 161 insertions, 212 deletions
diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java
index 98439ee7f..6874daea3 100644
--- a/java/com/android/incallui/answer/impl/AnswerFragment.java
+++ b/java/com/android/incallui/answer/impl/AnswerFragment.java
@@ -37,7 +37,6 @@ import android.support.annotation.StringRes;
import android.support.annotation.VisibleForTesting;
import android.support.transition.TransitionManager;
import android.support.v4.app.Fragment;
-import android.telecom.VideoProfile;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -79,10 +78,11 @@ import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
import com.android.incallui.incall.protocol.PrimaryCallState;
import com.android.incallui.incall.protocol.PrimaryInfo;
import com.android.incallui.incall.protocol.SecondaryInfo;
-import com.android.incallui.maps.StaticMapBinding;
+import com.android.incallui.maps.MapsComponent;
import com.android.incallui.sessiondata.AvatarPresenter;
import com.android.incallui.sessiondata.MultimediaFragment;
import com.android.incallui.util.AccessibilityUtil;
+import com.android.incallui.video.protocol.VideoCallScreen;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -101,7 +101,7 @@ public class AnswerFragment extends Fragment
static final String ARG_CALL_ID = "call_id";
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String ARG_VIDEO_STATE = "video_state";
+ static final String ARG_IS_VIDEO_CALL = "is_video_call";
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static final String ARG_IS_VIDEO_UPGRADE_REQUEST = "is_video_upgrade_request";
@@ -143,7 +143,7 @@ public class AnswerFragment extends Fragment
private CreateCustomSmsDialogFragment createCustomSmsDialogFragment;
private SecondaryBehavior secondaryBehavior = SecondaryBehavior.REJECT_WITH_SMS;
private ContactGridManager contactGridManager;
- private AnswerVideoCallScreen answerVideoCallScreen;
+ private VideoCallScreen answerVideoCallScreen;
private Handler handler = new Handler(Looper.getMainLooper());
private enum SecondaryBehavior {
@@ -288,10 +288,10 @@ public class AnswerFragment extends Fragment
}
public static AnswerFragment newInstance(
- String callId, int videoState, boolean isVideoUpgradeRequest) {
+ String callId, boolean isVideoCall, boolean isVideoUpgradeRequest) {
Bundle bundle = new Bundle();
bundle.putString(ARG_CALL_ID, Assert.isNotNull(callId));
- bundle.putInt(ARG_VIDEO_STATE, videoState);
+ bundle.putBoolean(ARG_IS_VIDEO_CALL, isVideoCall);
bundle.putBoolean(ARG_IS_VIDEO_UPGRADE_REQUEST, isVideoUpgradeRequest);
AnswerFragment instance = new AnswerFragment();
@@ -306,18 +306,13 @@ public class AnswerFragment extends Fragment
}
@Override
- public int getVideoState() {
- return getArguments().getInt(ARG_VIDEO_STATE);
- }
-
- @Override
public boolean isVideoUpgradeRequest() {
return getArguments().getBoolean(ARG_IS_VIDEO_UPGRADE_REQUEST);
}
@Override
public void setTextResponses(List<String> textResponses) {
- if (isVideoCall()) {
+ if (isVideoCall() || isVideoUpgradeRequest()) {
LogUtil.i("AnswerFragment.setTextResponses", "no-op for video calls");
} else if (textResponses == null) {
LogUtil.i("AnswerFragment.setTextResponses", "no text responses, hiding secondary button");
@@ -336,7 +331,9 @@ public class AnswerFragment extends Fragment
private void initSecondaryButton() {
secondaryBehavior =
- isVideoCall() ? SecondaryBehavior.ANSWER_VIDEO_AS_AUDIO : SecondaryBehavior.REJECT_WITH_SMS;
+ isVideoCall() || isVideoUpgradeRequest()
+ ? SecondaryBehavior.ANSWER_VIDEO_AS_AUDIO
+ : SecondaryBehavior.REJECT_WITH_SMS;
secondaryBehavior.applyToView(secondaryButton);
secondaryButton.setOnClickListener(
@@ -351,12 +348,9 @@ public class AnswerFragment extends Fragment
secondaryButton.setAccessibilityDelegate(accessibilityDelegate);
if (isVideoCall()) {
- //noinspection WrongConstant
- if (!isVideoUpgradeRequest() && VideoProfile.isTransmissionEnabled(getVideoState())) {
- secondaryButton.setVisibility(View.VISIBLE);
- } else {
- secondaryButton.setVisibility(View.INVISIBLE);
- }
+ secondaryButton.setVisibility(View.VISIBLE);
+ } else {
+ secondaryButton.setVisibility(View.INVISIBLE);
}
}
@@ -448,11 +442,11 @@ public class AnswerFragment extends Fragment
MultimediaData multimediaData = getSessionData();
if (multimediaData != null
- && (!TextUtils.isEmpty(multimediaData.getSubject())
+ && (!TextUtils.isEmpty(multimediaData.getText())
|| (multimediaData.getImageUri() != null)
|| (multimediaData.getLocation() != null && canShowMap()))) {
// Need message fragment
- String subject = multimediaData.getSubject();
+ String subject = multimediaData.getText();
Uri imageUri = multimediaData.getImageUri();
Location location = multimediaData.getLocation();
if (!(current instanceof MultimediaFragment)
@@ -487,11 +481,11 @@ public class AnswerFragment extends Fragment
}
private boolean shouldShowAvatar() {
- return !isVideoCall();
+ return !isVideoCall() && !isVideoUpgradeRequest();
}
private boolean canShowMap() {
- return StaticMapBinding.get(getActivity().getApplication()) != null;
+ return MapsComponent.get(getContext()).getMaps().isAvailable();
}
@Override
@@ -564,7 +558,7 @@ public class AnswerFragment extends Fragment
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle arguments = getArguments();
Assert.checkState(arguments.containsKey(ARG_CALL_ID));
- Assert.checkState(arguments.containsKey(ARG_VIDEO_STATE));
+ Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_CALL));
Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_UPGRADE_REQUEST));
buttonAcceptClicked = false;
@@ -596,7 +590,6 @@ public class AnswerFragment extends Fragment
});
updateImportanceBadgeVisibility();
- boolean isVideoCall = isVideoCall();
contactGridManager = new ContactGridManager(view, null, 0, false /* showAnonymousAvatar */);
Fragment answerMethod =
@@ -625,9 +618,9 @@ public class AnswerFragment extends Fragment
flags |= STATUS_BAR_DISABLE_BACK | STATUS_BAR_DISABLE_HOME | STATUS_BAR_DISABLE_RECENT;
}
view.setSystemUiVisibility(flags);
- if (isVideoCall) {
+ if (isVideoCall() || isVideoUpgradeRequest()) {
if (VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
- answerVideoCallScreen = new AnswerVideoCallScreen(this, view);
+ answerVideoCallScreen = new AnswerVideoCallScreen(getCallId(), this, view);
} else {
view.findViewById(R.id.videocall_video_off).setVisibility(View.VISIBLE);
}
@@ -649,7 +642,7 @@ public class AnswerFragment extends Fragment
updateUI();
if (savedInstanceState == null || !savedInstanceState.getBoolean(STATE_HAS_ANIMATED_ENTRY)) {
- ViewUtil.doOnPreDraw(view, false, this::animateEntry);
+ ViewUtil.doOnGlobalLayout(view, this::animateEntry);
}
}
@@ -667,7 +660,7 @@ public class AnswerFragment extends Fragment
updateUI();
if (answerVideoCallScreen != null) {
- answerVideoCallScreen.onStart();
+ answerVideoCallScreen.onVideoScreenStart();
}
}
@@ -678,7 +671,7 @@ public class AnswerFragment extends Fragment
handler.removeCallbacks(swipeHintRestoreTimer);
if (answerVideoCallScreen != null) {
- answerVideoCallScreen.onStop();
+ answerVideoCallScreen.onVideoScreenStop();
}
}
@@ -722,7 +715,7 @@ public class AnswerFragment extends Fragment
@Override
public boolean isVideoCall() {
- return VideoUtils.isVideoCall(getVideoState());
+ return getArguments().getBoolean(ARG_IS_VIDEO_CALL);
}
@Override
@@ -775,14 +768,12 @@ public class AnswerFragment extends Fragment
Animator dataContainer = createTranslation(rootView.findViewById(R.id.incall_data_container));
AnimatorSet animatorSet = new AnimatorSet();
- animatorSet
- .play(alpha)
- .with(topRow)
- .with(contactName)
- .with(bottomRow)
- .with(important)
- .with(dataContainer);
- animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
+ AnimatorSet.Builder builder = animatorSet.play(alpha);
+ builder.with(topRow).with(contactName).with(bottomRow).with(important).with(dataContainer);
+ if (isShowingLocationUi()) {
+ builder.with(createTranslation(rootView.findViewById(R.id.incall_location_holder)));
+ }
+ animatorSet.setDuration(getResources().getInteger(R.integer.answer_animate_entry_millis));
animatorSet.addListener(
new AnimatorListenerAdapter() {
@Override
@@ -803,14 +794,7 @@ public class AnswerFragment extends Fragment
private void acceptCallByUser(boolean answerVideoAsAudio) {
LogUtil.i("AnswerFragment.acceptCallByUser", answerVideoAsAudio ? " answerVideoAsAudio" : "");
if (!buttonAcceptClicked) {
- int desiredVideoState = getVideoState();
- if (answerVideoAsAudio) {
- desiredVideoState = VideoProfile.STATE_AUDIO_ONLY;
- }
-
- // Notify the lower layer first to start signaling ASAP.
- answerScreenDelegate.onAnswer(desiredVideoState);
-
+ answerScreenDelegate.onAnswer(answerVideoAsAudio);
buttonAcceptClicked = true;
}
}
diff --git a/java/com/android/incallui/answer/impl/AnswerVideoCallScreen.java b/java/com/android/incallui/answer/impl/AnswerVideoCallScreen.java
index 0316a5fab..06502daab 100644
--- a/java/com/android/incallui/answer/impl/AnswerVideoCallScreen.java
+++ b/java/com/android/incallui/answer/impl/AnswerVideoCallScreen.java
@@ -32,12 +32,15 @@ import com.android.incallui.videosurface.bindings.VideoSurfaceBindings;
/** Shows a video preview for an incoming call. */
public class AnswerVideoCallScreen implements VideoCallScreen {
+ @NonNull private final String callId;
@NonNull private final Fragment fragment;
@NonNull private final TextureView textureView;
@NonNull private final VideoCallScreenDelegate delegate;
- public AnswerVideoCallScreen(@NonNull Fragment fragment, @NonNull View view) {
- this.fragment = fragment;
+ public AnswerVideoCallScreen(
+ @NonNull String callId, @NonNull Fragment fragment, @NonNull View view) {
+ this.callId = Assert.isNotNull(callId);
+ this.fragment = Assert.isNotNull(fragment);
textureView =
Assert.isNotNull((TextureView) view.findViewById(R.id.incoming_preview_texture_view));
@@ -53,13 +56,15 @@ public class AnswerVideoCallScreen implements VideoCallScreen {
overlayView.setVisibility(View.VISIBLE);
}
- public void onStart() {
+ @Override
+ public void onVideoScreenStart() {
LogUtil.i("AnswerVideoCallScreen.onStart", null);
delegate.onVideoCallScreenUiReady();
delegate.getLocalVideoSurfaceTexture().attachToTextureView(textureView);
}
- public void onStop() {
+ @Override
+ public void onVideoScreenStop() {
LogUtil.i("AnswerVideoCallScreen.onStop", null);
delegate.onVideoCallScreenUiUnready();
}
@@ -98,6 +103,12 @@ public class AnswerVideoCallScreen implements VideoCallScreen {
return fragment;
}
+ @NonNull
+ @Override
+ public String getCallId() {
+ return callId;
+ }
+
private void updatePreviewVideoScaling() {
if (textureView.getWidth() == 0 || textureView.getHeight() == 0) {
LogUtil.i(
diff --git a/java/com/android/incallui/answer/impl/affordance/SwipeButtonHelper.java b/java/com/android/incallui/answer/impl/affordance/SwipeButtonHelper.java
index 62845b748..ff20d3a05 100644
--- a/java/com/android/incallui/answer/impl/affordance/SwipeButtonHelper.java
+++ b/java/com/android/incallui/answer/impl/affordance/SwipeButtonHelper.java
@@ -190,7 +190,7 @@ public class SwipeButtonHelper {
case MotionEvent.ACTION_UP:
isUp = true;
- //fallthrough_intended
+ // fall through
case MotionEvent.ACTION_CANCEL:
boolean hintOnTheRight = targetedView == rightIcon;
trackMovement(event);
diff --git a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java
index 4052281b7..afa194f2e 100644
--- a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java
+++ b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java
@@ -44,4 +44,6 @@ public interface AnswerMethodHolder {
* @return true iff the current call is a video call.
*/
boolean isVideoCall();
+
+ boolean isVideoUpgradeRequest();
}
diff --git a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
index 0bc65818c..6e8e1f7bf 100644
--- a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
+++ b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
@@ -60,7 +60,7 @@ import com.android.incallui.answer.impl.answermethod.FlingUpDownTouchHandler.OnP
import com.android.incallui.answer.impl.classifier.FalsingManager;
import com.android.incallui.answer.impl.hint.AnswerHint;
import com.android.incallui.answer.impl.hint.AnswerHintFactory;
-import com.android.incallui.answer.impl.hint.EventPayloadLoaderImpl;
+import com.android.incallui.answer.impl.hint.PawImageLoaderImpl;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -228,7 +228,7 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged
touchHandler = FlingUpDownTouchHandler.attach(view, this, falsingManager);
answerHint =
- new AnswerHintFactory(new EventPayloadLoaderImpl())
+ new AnswerHintFactory(new PawImageLoaderImpl())
.create(getContext(), ANIMATE_DURATION_LONG_MILLIS, BOUNCE_ANIMATION_DELAY);
answerHint.onCreateView(
layoutInflater,
@@ -319,7 +319,7 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged
if (contactPuckIcon == null) {
return;
}
- if (getParent().isVideoCall()) {
+ if (getParent().isVideoCall() || getParent().isVideoUpgradeRequest()) {
contactPuckIcon.setImageResource(R.drawable.quantum_ic_videocam_white_24);
} else {
contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24);
@@ -348,7 +348,8 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged
}
private boolean shouldShowPhotoInPuck() {
- return getParent().isVideoCall() && contactPhoto != null;
+ return (getParent().isVideoCall() || getParent().isVideoUpgradeRequest())
+ && contactPhoto != null;
}
@Override
@@ -387,6 +388,10 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged
// Since the animation progression is controlled by user gesture instead of real timeline, the
// spec timeline can be divided into 9 slots. Each slot is equivalent to 83ms in the spec.
// Therefore, we use 9 slots of 83ms to map user gesture into the spec timeline.
+ //
+ // See specs -
+ // Accept: https://direct.googleplex.com/#/spec/8510001
+ // Decline: https://direct.googleplex.com/#/spec/3850001
final float progressSlots = 9;
// Fade out the "swipe up to answer". It only takes 1 slot to complete the fade.
@@ -414,7 +419,7 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged
contactPuckBackground.setColorFilter(destPuckColor);
// Animate decline icon
- if (isAcceptingFlow || getParent().isVideoCall()) {
+ if (isAcceptingFlow || getParent().isVideoCall() || getParent().isVideoUpgradeRequest()) {
rotateToward(contactPuckIcon, 0f);
} else {
rotateToward(contactPuckIcon, positiveAdjustedProgress * ICON_END_CALL_ROTATION_DEGREES);
diff --git a/java/com/android/incallui/answer/impl/hint/AndroidManifest.xml b/java/com/android/incallui/answer/impl/hint/AndroidManifest.xml
index b5fa6da8f..dfbba1cbf 100644
--- a/java/com/android/incallui/answer/impl/hint/AndroidManifest.xml
+++ b/java/com/android/incallui/answer/impl/hint/AndroidManifest.xml
@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<application>
- <receiver android:name=".EventSecretCodeListener">
+ <receiver android:name=".PawSecretCodeListener">
<intent-filter>
<action android:name="android.provider.Telephony.SECRET_CODE" />
<data android:scheme="android_secret_code" />
diff --git a/java/com/android/incallui/answer/impl/hint/AnswerHintFactory.java b/java/com/android/incallui/answer/impl/hint/AnswerHintFactory.java
index 45395a71f..eaf5b74e5 100644
--- a/java/com/android/incallui/answer/impl/hint/AnswerHintFactory.java
+++ b/java/com/android/incallui/answer/impl/hint/AnswerHintFactory.java
@@ -28,7 +28,6 @@ import com.android.dialer.common.ConfigProvider;
import com.android.dialer.common.ConfigProviderBindings;
import com.android.dialer.common.LogUtil;
import com.android.incallui.util.AccessibilityUtil;
-import java.util.Calendar;
/**
* Selects a AnswerHint to show. If there's no suitable hints {@link EmptyAnswerHint} will be used,
@@ -51,10 +50,10 @@ public class AnswerHintFactory {
@VisibleForTesting
static final String ANSWERED_COUNT_PREFERENCE_KEY = "answer_hint_answered_count";
- private final EventPayloadLoader eventPayloadLoader;
+ private final PawImageLoader pawImageLoader;
- public AnswerHintFactory(@NonNull EventPayloadLoader eventPayloadLoader) {
- this.eventPayloadLoader = Assert.isNotNull(eventPayloadLoader);
+ public AnswerHintFactory(@NonNull PawImageLoader pawImageLoader) {
+ this.pawImageLoader = Assert.isNotNull(pawImageLoader);
}
@NonNull
@@ -69,11 +68,9 @@ public class AnswerHintFactory {
}
// Display the event answer hint if the payload is available.
- Drawable eventPayload =
- eventPayloadLoader.loadPayload(
- context, System.currentTimeMillis(), Calendar.getInstance().getTimeZone());
+ Drawable eventPayload = pawImageLoader.loadPayload(context);
if (eventPayload != null) {
- return new EventAnswerHint(context, eventPayload, puckUpDuration, puckUpDelay);
+ return new PawAnswerHint(context, eventPayload, puckUpDuration, puckUpDelay);
}
return new EmptyAnswerHint();
diff --git a/java/com/android/incallui/answer/impl/hint/EventPayloadLoaderImpl.java b/java/com/android/incallui/answer/impl/hint/EventPayloadLoaderImpl.java
deleted file mode 100644
index bd8d73645..000000000
--- a/java/com/android/incallui/answer/impl/hint/EventPayloadLoaderImpl.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.incallui.answer.impl.hint;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build.VERSION_CODES;
-import android.preference.PreferenceManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.ConfigProvider;
-import com.android.dialer.common.ConfigProviderBindings;
-import com.android.dialer.common.LogUtil;
-import java.io.InputStream;
-import java.util.TimeZone;
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-
-/** Decrypt the event payload to be shown if in a specific time range and the key is received. */
-@TargetApi(VERSION_CODES.M)
-public final class EventPayloadLoaderImpl implements EventPayloadLoader {
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String CONFIG_EVENT_KEY = "event_key";
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String CONFIG_EVENT_BINARY = "event_binary";
-
- // Time is stored as a UTC UNIX timestamp in milliseconds, but interpreted as local time.
- // For example, 946684800 (2000/1/1 00:00:00 @UTC) is the new year midnight at every timezone.
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String CONFIG_EVENT_START_UTC_AS_LOCAL_MILLIS = "event_time_start_millis";
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String CONFIG_EVENT_TIME_END_UTC_AS_LOCAL_MILLIS = "event_time_end_millis";
-
- @Override
- @Nullable
- public Drawable loadPayload(
- @NonNull Context context, long currentTimeUtcMillis, @NonNull TimeZone timeZone) {
- Assert.isNotNull(context);
- Assert.isNotNull(timeZone);
- ConfigProvider configProvider = ConfigProviderBindings.get(context);
-
- String pbeKey = configProvider.getString(CONFIG_EVENT_KEY, null);
- if (pbeKey == null) {
- return null;
- }
- long timeRangeStart = configProvider.getLong(CONFIG_EVENT_START_UTC_AS_LOCAL_MILLIS, 0);
- long timeRangeEnd = configProvider.getLong(CONFIG_EVENT_TIME_END_UTC_AS_LOCAL_MILLIS, 0);
-
- String eventBinary = configProvider.getString(CONFIG_EVENT_BINARY, null);
- if (eventBinary == null) {
- return null;
- }
-
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
- if (!preferences.getBoolean(
- EventSecretCodeListener.EVENT_ENABLED_WITH_SECRET_CODE_KEY, false)) {
- long localTimestamp = currentTimeUtcMillis + timeZone.getRawOffset();
-
- if (localTimestamp < timeRangeStart) {
- return null;
- }
-
- if (localTimestamp > timeRangeEnd) {
- return null;
- }
- }
-
- // Use openssl aes-128-cbc -in <input> -out <output> -pass <PBEKey> to generate the asset
- try (InputStream input = context.getAssets().open(eventBinary)) {
- byte[] encryptedFile = new byte[input.available()];
- input.read(encryptedFile);
-
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
-
- byte[] salt = new byte[8];
- System.arraycopy(encryptedFile, 8, salt, 0, 8);
- SecretKey key =
- SecretKeyFactory.getInstance("PBEWITHMD5AND128BITAES-CBC-OPENSSL", "BC")
- .generateSecret(new PBEKeySpec(pbeKey.toCharArray(), salt, 100));
- cipher.init(Cipher.DECRYPT_MODE, key);
-
- byte[] decryptedFile = cipher.doFinal(encryptedFile, 16, encryptedFile.length - 16);
-
- return new BitmapDrawable(
- context.getResources(),
- BitmapFactory.decodeByteArray(decryptedFile, 0, decryptedFile.length));
- } catch (Exception e) {
- // Avoid crashing dialer for any reason.
- LogUtil.e("EventPayloadLoader.loadPayload", "error decrypting payload:", e);
- return null;
- }
- }
-}
diff --git a/java/com/android/incallui/answer/impl/hint/EventAnswerHint.java b/java/com/android/incallui/answer/impl/hint/PawAnswerHint.java
index 7ee327d50..36b761f57 100644
--- a/java/com/android/incallui/answer/impl/hint/EventAnswerHint.java
+++ b/java/com/android/incallui/answer/impl/hint/PawAnswerHint.java
@@ -39,7 +39,7 @@ import com.android.dialer.common.Assert;
* An Answer hint that animates a {@link Drawable} payload with animation similar to {@link
* DotAnswerHint}.
*/
-public final class EventAnswerHint implements AnswerHint {
+public final class PawAnswerHint implements AnswerHint {
private static final long FADE_IN_DELAY_SCALE_MILLIS = 380;
private static final long FADE_IN_DURATION_SCALE_MILLIS = 200;
@@ -53,7 +53,8 @@ public final class EventAnswerHint implements AnswerHint {
private static final long FADE_OUT_DELAY_ALPHA_MILLIS = 130;
private static final long FADE_OUT_DURATION_ALPHA_MILLIS = 170;
- private static final float FADE_SCALE = 1.2f;
+ private static final float IMAGE_SCALE = 1.5f;
+ private static final float FADE_SCALE = 2.0f;
private final Context context;
private final Drawable payload;
@@ -65,7 +66,7 @@ public final class EventAnswerHint implements AnswerHint {
private View answerHintContainer;
private AnimatorSet answerGestureHintAnim;
- public EventAnswerHint(
+ public PawAnswerHint(
@NonNull Context context,
@NonNull Drawable payload,
long puckUpDurationMillis,
@@ -80,9 +81,9 @@ public final class EventAnswerHint implements AnswerHint {
public void onCreateView(
LayoutInflater inflater, ViewGroup container, View puck, TextView hintText) {
this.puck = puck;
- View view = inflater.inflate(R.layout.event_hint, container, true);
+ View view = inflater.inflate(R.layout.paw_hint, container, true);
answerHintContainer = view.findViewById(R.id.answer_hint_container);
- payloadView = view.findViewById(R.id.payload);
+ payloadView = view.findViewById(R.id.paw_image);
hintText.setTextSize(
TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.hint_text_size));
((ImageView) payloadView).setImageDrawable(payload);
@@ -143,7 +144,7 @@ public final class EventAnswerHint implements AnswerHint {
createUniformScaleAnimator(
target,
FADE_SCALE,
- 1.0f,
+ IMAGE_SCALE,
FADE_IN_DURATION_SCALE_MILLIS,
FADE_IN_DELAY_SCALE_MILLIS,
new LinearInterpolator());
@@ -170,7 +171,7 @@ public final class EventAnswerHint implements AnswerHint {
Animator scale =
createUniformScaleAnimator(
target,
- 1.0f,
+ IMAGE_SCALE,
FADE_SCALE,
FADE_OUT_DURATION_SCALE_MILLIS,
scaleDelay,
@@ -178,7 +179,7 @@ public final class EventAnswerHint implements AnswerHint {
Animator alpha =
createAlphaAnimator(
target,
- 01.0f,
+ 1.0f,
0.0f,
FADE_OUT_DURATION_ALPHA_MILLIS,
FADE_OUT_DELAY_ALPHA_MILLIS,
diff --git a/java/com/android/incallui/answer/impl/hint/EventPayloadLoader.java b/java/com/android/incallui/answer/impl/hint/PawImageLoader.java
index 09e3bedf2..09e700fe0 100644
--- a/java/com/android/incallui/answer/impl/hint/EventPayloadLoader.java
+++ b/java/com/android/incallui/answer/impl/hint/PawImageLoader.java
@@ -20,11 +20,9 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import java.util.TimeZone;
-/** Loads a {@link Drawable} payload for the {@link EventAnswerHint} if it should be displayed. */
-public interface EventPayloadLoader {
+/** Loads a {@link Drawable} payload for the {@link PawAnswerHint} if it should be displayed. */
+public interface PawImageLoader {
@Nullable
- Drawable loadPayload(
- @NonNull Context context, long currentTimeUtcMillis, @NonNull TimeZone timeZone);
+ Drawable loadPayload(@NonNull Context context);
}
diff --git a/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java b/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java
new file mode 100644
index 000000000..485a9ae37
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.answer.impl.hint;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION_CODES;
+import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import com.android.dialer.common.Assert;
+
+/** Decrypt the event payload to be shown if in a specific time range and the key is received. */
+@TargetApi(VERSION_CODES.M)
+public final class PawImageLoaderImpl implements PawImageLoader {
+
+ @Override
+ @Nullable
+ public Drawable loadPayload(@NonNull Context context) {
+ Assert.isNotNull(context);
+
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+ if (!preferences.getBoolean(PawSecretCodeListener.PAW_ENABLED_WITH_SECRET_CODE_KEY, false)) {
+ return null;
+ }
+ int drawableId = preferences.getInt(PawSecretCodeListener.PAW_DRAWABLE_ID_KEY, 0);
+ if (drawableId == 0) {
+ return null;
+ }
+ return context.getDrawable(drawableId);
+ }
+}
diff --git a/java/com/android/incallui/answer/impl/hint/EventSecretCodeListener.java b/java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java
index 7cf4054a9..b4fc19c0d 100644
--- a/java/com/android/incallui/answer/impl/hint/EventSecretCodeListener.java
+++ b/java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java
@@ -24,26 +24,30 @@ import android.preference.PreferenceManager;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.widget.Toast;
+import com.android.dialer.common.Assert;
import com.android.dialer.common.ConfigProviderBindings;
import com.android.dialer.common.LogUtil;
import com.android.dialer.logging.Logger;
-import com.android.dialer.logging.nano.DialerImpression;
+import com.android.dialer.logging.nano.DialerImpression.Type;
+import java.util.Random;
/**
* Listen to the broadcast when the user dials "*#*#[number]#*#*" to toggle the event answer hint.
*/
-public class EventSecretCodeListener extends BroadcastReceiver {
+public class PawSecretCodeListener extends BroadcastReceiver {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String CONFIG_EVENT_SECRET_CODE = "event_secret_code";
+ static final String CONFIG_PAW_SECRET_CODE = "paw_secret_code";
- public static final String EVENT_ENABLED_WITH_SECRET_CODE_KEY = "event_enabled_with_secret_code";
+ public static final String PAW_ENABLED_WITH_SECRET_CODE_KEY = "paw_enabled_with_secret_code";
+ public static final String PAW_DRAWABLE_ID_KEY = "paw_drawable_id";
@Override
public void onReceive(Context context, Intent intent) {
String host = intent.getData().getHost();
+ Assert.checkState(!TextUtils.isEmpty(host));
String secretCode =
- ConfigProviderBindings.get(context).getString(CONFIG_EVENT_SECRET_CODE, null);
+ ConfigProviderBindings.get(context).getString(CONFIG_PAW_SECRET_CODE, "729");
if (secretCode == null) {
return;
}
@@ -51,17 +55,27 @@ public class EventSecretCodeListener extends BroadcastReceiver {
return;
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
- boolean wasEnabled = preferences.getBoolean(EVENT_ENABLED_WITH_SECRET_CODE_KEY, false);
+ boolean wasEnabled = preferences.getBoolean(PAW_ENABLED_WITH_SECRET_CODE_KEY, false);
if (wasEnabled) {
- preferences.edit().putBoolean(EVENT_ENABLED_WITH_SECRET_CODE_KEY, false).apply();
+ preferences.edit().putBoolean(PAW_ENABLED_WITH_SECRET_CODE_KEY, false).apply();
Toast.makeText(context, R.string.event_deactivated, Toast.LENGTH_SHORT).show();
- Logger.get(context).logImpression(DialerImpression.Type.EVENT_ANSWER_HINT_DEACTIVATED);
- LogUtil.i("EventSecretCodeListener.onReceive", "EventAnswerHint disabled");
+ Logger.get(context).logImpression(Type.EVENT_ANSWER_HINT_DEACTIVATED);
+ LogUtil.i("PawSecretCodeListener.onReceive", "PawAnswerHint disabled");
} else {
- preferences.edit().putBoolean(EVENT_ENABLED_WITH_SECRET_CODE_KEY, true).apply();
+ int drawableId;
+ if (new Random().nextBoolean()) {
+ drawableId = R.drawable.cat_paw;
+ } else {
+ drawableId = R.drawable.dog_paw;
+ }
+ preferences
+ .edit()
+ .putBoolean(PAW_ENABLED_WITH_SECRET_CODE_KEY, true)
+ .putInt(PAW_DRAWABLE_ID_KEY, drawableId)
+ .apply();
Toast.makeText(context, R.string.event_activated, Toast.LENGTH_SHORT).show();
- Logger.get(context).logImpression(DialerImpression.Type.EVENT_ANSWER_HINT_ACTIVATED);
- LogUtil.i("EventSecretCodeListener.onReceive", "EventAnswerHint enabled");
+ Logger.get(context).logImpression(Type.EVENT_ANSWER_HINT_ACTIVATED);
+ LogUtil.i("PawSecretCodeListener.onReceive", "PawAnswerHint enabled");
}
}
}
diff --git a/java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/cat_paw.webp b/java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/cat_paw.webp
new file mode 100644
index 000000000..f7ff6eb54
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/cat_paw.webp
Binary files differ
diff --git a/java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/dog_paw.webp b/java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/dog_paw.webp
new file mode 100644
index 000000000..3a232542c
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/hint/res/drawable-xxhdpi/dog_paw.webp
Binary files differ
diff --git a/java/com/android/incallui/answer/impl/hint/res/layout/event_hint.xml b/java/com/android/incallui/answer/impl/hint/res/layout/paw_hint.xml
index d505014c1..c3b12a01d 100644
--- a/java/com/android/incallui/answer/impl/hint/res/layout/event_hint.xml
+++ b/java/com/android/incallui/answer/impl/hint/res/layout/paw_hint.xml
@@ -24,9 +24,10 @@
android:clipToPadding="false"
android:visibility="gone">
<ImageView
- android:id="@+id/payload"
- android:layout_width="191dp"
- android:layout_height="773dp"
+ android:id="@+id/paw_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/cat_paw"
android:layout_gravity="center"
android:alpha="0"
android:rotation="-30"
diff --git a/java/com/android/incallui/answer/impl/proguard.flags b/java/com/android/incallui/answer/impl/proguard.flags
new file mode 100644
index 000000000..016352857
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/proguard.flags
@@ -0,0 +1,5 @@
+# Used in com.android.dialer.answer.impl.SmsBottomSheetFragment
+-keep class android.support.design.widget.BottomSheetBehavior {
+ public <init>(android.content.Context, android.util.AttributeSet);
+ public <init>();
+} \ No newline at end of file
diff --git a/java/com/android/incallui/answer/impl/res/values/dimens.xml b/java/com/android/incallui/answer/impl/res/values/dimens.xml
index c48b68f93..8329707a6 100644
--- a/java/com/android/incallui/answer/impl/res/values/dimens.xml
+++ b/java/com/android/incallui/answer/impl/res/values/dimens.xml
@@ -22,4 +22,5 @@
<dimen name="answer_avatar_size">0dp</dimen>
<dimen name="answer_importance_margin_bottom">0dp</dimen>
<bool name="answer_important_call_allowed">false</bool>
+ <integer name="answer_animate_entry_millis">1000</integer>
</resources>