diff options
Diffstat (limited to 'java/com/android/incallui/incall/impl')
7 files changed, 291 insertions, 26 deletions
diff --git a/java/com/android/incallui/incall/impl/AndroidManifest.xml b/java/com/android/incallui/incall/impl/AndroidManifest.xml index a0e3110d8..3d646506d 100644 --- a/java/com/android/incallui/incall/impl/AndroidManifest.xml +++ b/java/com/android/incallui/incall/impl/AndroidManifest.xml @@ -1,3 +1 @@ -<manifest - package="com.android.incall.incall.impl"> -</manifest> +<manifest package="com.android.incallui.incall.impl"/> diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java index b6ae4902a..02e9b4add 100644 --- a/java/com/android/incallui/incall/impl/InCallFragment.java +++ b/java/com/android/incallui/incall/impl/InCallFragment.java @@ -25,11 +25,9 @@ import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; -import android.support.v4.view.ViewPager; import android.telecom.CallAudioState; import android.telephony.TelephonyManager; import android.view.LayoutInflater; @@ -74,8 +72,8 @@ public class InCallFragment extends Fragment private List<ButtonController> buttonControllers = new ArrayList<>(); private View endCallButton; - private TabLayout tabLayout; - private ViewPager pager; + private InCallPaginator paginator; + private LockableViewPager pager; private InCallPagerAdapter adapter; private ContactGridManager contactGridManager; private InCallScreenDelegate inCallScreenDelegate; @@ -134,8 +132,8 @@ public class InCallFragment extends Fragment getResources().getDimensionPixelSize(R.dimen.incall_avatar_size), true /* showAnonymousAvatar */); - tabLayout = (TabLayout) view.findViewById(R.id.incall_tab_dots); - pager = (ViewPager) view.findViewById(R.id.incall_pager); + paginator = (InCallPaginator) view.findViewById(R.id.incall_paginator); + pager = (LockableViewPager) view.findViewById(R.id.incall_pager); endCallButton = view.findViewById(R.id.incall_end_call); endCallButton.setOnClickListener(this); @@ -248,8 +246,8 @@ public class InCallFragment extends Fragment } if (adapter.getCount() > 1) { - tabLayout.setVisibility(pager.getVisibility()); - tabLayout.setupWithViewPager(pager, true); + paginator.setVisibility(View.VISIBLE); + paginator.setupWithViewPager(pager); if (!stateRestored) { new Handler() .postDelayed( @@ -263,9 +261,9 @@ public class InCallFragment extends Fragment } }, 2000); + } else { + paginator.setVisibility(View.GONE); } - } else { - tabLayout.setVisibility(View.GONE); } } @@ -428,8 +426,15 @@ public class InCallFragment extends Fragment int visibility = numVisibleButtons == 0 ? View.GONE : View.VISIBLE; pager.setVisibility(visibility); - if (adapter != null && adapter.getCount() > 1) { - tabLayout.setVisibility(visibility); + if (adapter != null + && adapter.getCount() > 1 + && getResources().getInteger(R.integer.incall_num_rows) > 1) { + paginator.setVisibility(View.VISIBLE); + pager.setSwipingLocked(false); + } else { + paginator.setVisibility(View.GONE); + pager.setSwipingLocked(true); + pager.setCurrentItem(adapter.getButtonGridPosition()); } } diff --git a/java/com/android/incallui/incall/impl/InCallPaginator.java b/java/com/android/incallui/incall/impl/InCallPaginator.java new file mode 100644 index 000000000..8ebbd76a2 --- /dev/null +++ b/java/com/android/incallui/incall/impl/InCallPaginator.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2017 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.incall.impl; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.support.annotation.VisibleForTesting; +import android.support.v4.view.ViewPager; +import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.util.AttributeSet; +import android.view.View; +import com.android.dialer.common.Assert; + +/** + * This is the view class for incall paginator visible when a user has EC data attached to their + * call. It contains animation methods when the swipe gesture is performed. + */ +public class InCallPaginator extends View implements OnPageChangeListener { + + private int dotRadius; + private int dotsSeparation; + + private Paint activeDotPaintPortrait; + private Paint inactiveDotPaintPortrait; + + private Path inactiveDotPath; + private ValueAnimator transitionAnimator; + private boolean useModeSwitchTransition; + + private float progress; + private boolean toFirstPage; + private boolean pageChanged; + + public InCallPaginator(Context context) { + super(context); + init(context); + } + + public InCallPaginator(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + private void init(Context context) { + dotRadius = getResources().getDimensionPixelSize(R.dimen.paginator_dot_radius); + dotsSeparation = getResources().getDimensionPixelSize(R.dimen.paginator_dots_separation); + + int activeDotColor = context.getColor(R.color.paginator_dot); + int inactiveDotColor = context.getColor(R.color.paginator_path); + activeDotPaintPortrait = new Paint(Paint.ANTI_ALIAS_FLAG); + activeDotPaintPortrait.setColor(activeDotColor); + inactiveDotPaintPortrait = new Paint(Paint.ANTI_ALIAS_FLAG); + inactiveDotPaintPortrait.setColor(inactiveDotColor); + + inactiveDotPath = new Path(); + transitionAnimator = ValueAnimator.ofFloat(0f, 1f); + transitionAnimator.setInterpolator(null); + transitionAnimator.setCurrentFraction(0f); + transitionAnimator.addUpdateListener(animation -> invalidate()); + } + + @VisibleForTesting + public void setProgress(float progress, boolean toFirstPage) { + this.progress = progress; + this.toFirstPage = toFirstPage; + + // Ensure the dot transition keeps up with the swipe progress. + if (transitionAnimator.isStarted() && progress > transitionAnimator.getAnimatedFraction()) { + transitionAnimator.setCurrentFraction(progress); + } + + invalidate(); + } + + private void startTransition() { + if (transitionAnimator.getAnimatedFraction() < 1f) { + transitionAnimator.setCurrentFraction(progress); + useModeSwitchTransition = false; + transitionAnimator.cancel(); + transitionAnimator.start(); + } + } + + private void endTransition(boolean snapBack) { + if (transitionAnimator.getAnimatedFraction() > 0f) { + useModeSwitchTransition = !snapBack; + transitionAnimator.cancel(); + transitionAnimator.reverse(); + } + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + float transitionFraction = (float) transitionAnimator.getAnimatedValue(); + + // Draw the inactive "dots". + inactiveDotPath.reset(); + if (useModeSwitchTransition) { + float trackWidth = 2 * dotRadius + transitionFraction * (2 * dotRadius + dotsSeparation); + float indicatorRadius = dotRadius * (1f - 2f * Math.min(transitionFraction, 0.5f)); + float indicatorOffset = dotRadius + dotsSeparation / 2; + if (toFirstPage) { + float trackLeft = centerX - indicatorOffset - dotRadius; + inactiveDotPath.addRoundRect( + trackLeft, + centerY - dotRadius, + trackLeft + trackWidth, + centerY + dotRadius, + dotRadius, + dotRadius, + Path.Direction.CW); + inactiveDotPath.addCircle( + centerX + indicatorOffset, centerY, indicatorRadius, Path.Direction.CW); + } else { + float trackRight = centerX + indicatorOffset + dotRadius; + inactiveDotPath.addRoundRect( + trackRight - trackWidth, + centerY - dotRadius, + trackRight, + centerY + dotRadius, + dotRadius, + dotRadius, + Path.Direction.CW); + inactiveDotPath.addCircle( + centerX - indicatorOffset, centerY, indicatorRadius, Path.Direction.CW); + } + } else { + float centerOffset = dotsSeparation / 2f; + float innerOffset = centerOffset - transitionFraction * (dotRadius + centerOffset); + float outerOffset = 2f * dotRadius + centerOffset; + inactiveDotPath.addRoundRect( + centerX - outerOffset, + centerY - dotRadius, + centerX - innerOffset, + centerY + dotRadius, + dotRadius, + dotRadius, + Path.Direction.CW); + inactiveDotPath.addRoundRect( + centerX + innerOffset, + centerY - dotRadius, + centerX + outerOffset, + centerY + dotRadius, + dotRadius, + dotRadius, + Path.Direction.CW); + } + Paint inactivePaint = inactiveDotPaintPortrait; + canvas.drawPath(inactiveDotPath, inactivePaint); + + // Draw the white active dot. + float activeDotOffset = + (toFirstPage ? 1f - 2f * progress : 2f * progress - 1f) * (dotRadius + dotsSeparation / 2); + Paint activePaint = activeDotPaintPortrait; + canvas.drawCircle(centerX + activeDotOffset, centerY, dotRadius, activePaint); + } + + public void setupWithViewPager(ViewPager pager) { + Assert.checkArgument(pager.getAdapter().getCount() == 2, "Invalid page count."); + pager.addOnPageChangeListener(this); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + setProgress(positionOffset, position != 0); + } + + @Override + public void onPageSelected(int position) { + pageChanged = true; + } + + @Override + public void onPageScrollStateChanged(int state) { + switch (state) { + case ViewPager.SCROLL_STATE_IDLE: + endTransition(!pageChanged); + pageChanged = false; + break; + case ViewPager.SCROLL_STATE_DRAGGING: + startTransition(); + break; + case ViewPager.SCROLL_STATE_SETTLING: + default: + break; + } + } +} diff --git a/java/com/android/incallui/incall/impl/LockableViewPager.java b/java/com/android/incallui/incall/impl/LockableViewPager.java new file mode 100644 index 000000000..5b8b12609 --- /dev/null +++ b/java/com/android/incallui/incall/impl/LockableViewPager.java @@ -0,0 +1,46 @@ +/* + * 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.incall.impl; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** {@link ViewPager} useful for disabled swiping between pages. */ +public class LockableViewPager extends ViewPager { + + private boolean swipingLocked; + + public LockableViewPager(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + } + + public void setSwipingLocked(boolean swipingLocked) { + this.swipingLocked = swipingLocked; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent motionEvent) { + return !swipingLocked && super.onInterceptTouchEvent(motionEvent); + } + + @Override + public boolean onTouchEvent(MotionEvent motionEvent) { + return !swipingLocked && super.onTouchEvent(motionEvent); + } +} diff --git a/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml b/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml index 9b950462c..e4bc942bb 100644 --- a/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml +++ b/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml @@ -60,23 +60,21 @@ android:layout_height="match_parent"/> </LinearLayout> - <android.support.v4.view.ViewPager + <com.android.incallui.incall.impl.LockableViewPager android:id="@+id/incall_pager" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_above="@+id/incall_tab_dots" + android:layout_above="@+id/incall_paginator" android:layout_below="@+id/incall_contact_grid" android:layout_centerHorizontal="true"/> - <android.support.design.widget.TabLayout - android:id="@+id/incall_tab_dots" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_above="@+id/incall_end_call" - android:visibility="gone" - app:tabBackground="@drawable/tab_selector" - app:tabGravity="center" - app:tabIndicatorHeight="0dp"/> + <com.android.incallui.incall.impl.InCallPaginator + android:id="@+id/incall_paginator" + android:layout_height="@dimen/paginator_height" + android:layout_width="@dimen/paginator_width" + android:layout_above="@+id/incall_end_call" + android:layout_centerHorizontal="true" + android:visibility="gone"/> <FrameLayout android:id="@+id/incall_dialpad_container" diff --git a/java/com/android/incallui/incall/impl/res/values/dimens.xml b/java/com/android/incallui/incall/impl/res/values/dimens.xml index 249788785..72602e3fc 100644 --- a/java/com/android/incallui/incall/impl/res/values/dimens.xml +++ b/java/com/android/incallui/incall/impl/res/values/dimens.xml @@ -14,4 +14,9 @@ <bool name="incall_dialpad_allowed">false</bool> <integer name="incall_num_rows">0</integer> + + <dimen name="paginator_dot_radius">5dp</dimen> + <dimen name="paginator_dots_separation">8dp</dimen> + <dimen name="paginator_height">38dp</dimen> + <dimen name="paginator_width">72dp</dimen> </resources> diff --git a/java/com/android/incallui/incall/impl/res/values/styles.xml b/java/com/android/incallui/incall/impl/res/values/styles.xml index 2392574a3..a8cf2ddf1 100644 --- a/java/com/android/incallui/incall/impl/res/values/styles.xml +++ b/java/com/android/incallui/incall/impl/res/values/styles.xml @@ -17,6 +17,9 @@ <resources> + <color name="paginator_dot">#FFF</color> + <color name="paginator_path">#66FFFFFF</color> + <style name="DialpadContainer"> <item name="android:layout_alignParentTop">true</item> </style> |