diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:25:49 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:25:49 +0000 |
commit | ad227a51653717857091f699955dde81964130c5 (patch) | |
tree | a8df9e8f080110b07aad539bd5ef8de0d4567477 | |
parent | 46b2ac6fa2f78122c0b766156b0e3fa449aaae72 (diff) | |
parent | 93393730aee9ead1703600dddbca4ac40a7d259e (diff) | |
download | setupwizard-q_tzdata_aml_297100000.tar.gz |
Snap for 6439596 from 93393730aee9ead1703600dddbca4ac40a7d259e to qt-aml-tzdata-releaseq_tzdata_aml_297100400q_tzdata_aml_297100300q_tzdata_aml_297100000q_tzdata_aml_296200000q_tzdata_aml_295600118q_tzdata_aml_295600110q_tzdata_aml_295500002q_tzdata_aml_295500001q_tzdata_aml_294400310android-mainline-12.0.0_r54android-mainline-12.0.0_r111android-mainline-10.0.0_r13android-mainline-10.0.0_r12android-mainline-10.0.0_r11q_tzdata_aml_297100000android12-mainline-tzdata-releaseandroid10-mainline-tzdata-releaseandroid10-android13-mainline-tzdata-release
Change-Id: Ib721738f03059473caead9e14dfd4f4c3ca678b7
25 files changed, 996 insertions, 239 deletions
diff --git a/library/main/res/anim/progress_indeterminate_horizontal_rect1.xml b/library/main/res/anim/progress_indeterminate_horizontal_rect1.xml new file mode 100644 index 0000000..b541364 --- /dev/null +++ b/library/main/res/anim/progress_indeterminate_horizontal_rect1.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="2000" + android:propertyXName="translateX" + android:pathData="M -522.59998,0 c 48.89972,0 166.02656,0 301.21729,0 c 197.58128,0 420.9827,0 420.9827,0 " + android:interpolator="@interpolator/progress_indeterminate_horizontal_rect1_translatex" + android:repeatCount="infinite" /> + <objectAnimator + android:duration="2000" + android:propertyYName="scaleX" + android:pathData="M 0 0.1 L 1 0.826849212646 L 2 0.1" + android:interpolator="@interpolator/progress_indeterminate_horizontal_rect1_scalex" + android:repeatCount="infinite" /> +</set>
\ No newline at end of file diff --git a/library/main/res/anim/progress_indeterminate_horizontal_rect2.xml b/library/main/res/anim/progress_indeterminate_horizontal_rect2.xml new file mode 100644 index 0000000..defc80f --- /dev/null +++ b/library/main/res/anim/progress_indeterminate_horizontal_rect2.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="2000" + android:propertyXName="translateX" + android:pathData="M -197.60001,0 c 14.28182,0 85.07782,0 135.54689,0 c 54.26191,0 90.42461,0 168.24331,0 c 144.72154,0 316.40982,0 316.40982,0 " + android:interpolator="@interpolator/progress_indeterminate_horizontal_rect2_translatex" + android:repeatCount="infinite" /> + <objectAnimator + android:duration="2000" + android:propertyYName="scaleX" + android:pathData="M 0.0,0.1 L 1.0,0.571379510698 L 2.0,0.909950256348 L 3.0,0.1" + android:interpolator="@interpolator/progress_indeterminate_horizontal_rect2_scalex" + android:repeatCount="infinite" /> +</set>
\ No newline at end of file diff --git a/library/main/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/library/main/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml new file mode 100644 index 0000000..e58fb30 --- /dev/null +++ b/library/main/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<animated-vector + xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed"> + <target + android:name="rect2_grp" + android:animation="@anim/progress_indeterminate_horizontal_rect2"/> + <target + android:name="rect1_grp" + android:animation="@anim/progress_indeterminate_horizontal_rect1"/> +</animated-vector>
\ No newline at end of file diff --git a/library/main/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/library/main/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml new file mode 100644 index 0000000..c34f96b --- /dev/null +++ b/library/main/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<vector + xmlns:android="http://schemas.android.com/apk/res/android" + android:width="360dp" + android:height="10dp" + android:viewportHeight="10" + android:viewportWidth="360"> + <group + android:name="progress_group" + android:translateX="180" + android:translateY="5"> + <path + android:name="background_track" + android:fillAlpha="?android:attr/disabledAlpha" + android:fillColor="?android:attr/colorControlActivated" + android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"/> + <group + android:name="rect2_grp" + android:scaleX="0.1" + android:translateX="-197.60001"> + <path + android:name="rect2" + android:fillColor="?android:attr/colorControlActivated" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"/> + </group> + <group + android:name="rect1_grp" + android:scaleX="0.1" + android:translateX="-522.59998"> + <path + android:name="rect1" + android:fillColor="?android:attr/colorControlActivated" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"/> + </group> + </group> +</vector>
\ No newline at end of file diff --git a/library/main/res/values/dimens.xml b/library/main/res/interpolator/progress_indeterminate_horizontal_rect1_scalex.xml index 4a66971..acf67a6 100644 --- a/library/main/res/values/dimens.xml +++ b/library/main/res/interpolator/progress_indeterminate_horizontal_rect1_scalex.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (C) 2018 The Android Open Source Project + Copyright (C) 2020 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 + 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, @@ -14,7 +14,5 @@ See the License for the specific language governing permissions and limitations under the License. --> -<resources> - <!-- Elevation used to create a drop shadow on the title bar. --> - <dimen name="title_bar_drop_shadow_elevation">16dp</dimen> -</resources>
\ No newline at end of file +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 L 0.3665 0 C 0.47252618112021,0.062409910275 0.61541608570164,0.5 0.68325,0.5 C 0.75475061236836,0.5 0.75725829093844,0.814510098964 1.0,1.0" />
\ No newline at end of file diff --git a/library/main/res/interpolator/progress_indeterminate_horizontal_rect1_translatex.xml b/library/main/res/interpolator/progress_indeterminate_horizontal_rect1_translatex.xml new file mode 100644 index 0000000..3b6b023 --- /dev/null +++ b/library/main/res/interpolator/progress_indeterminate_horizontal_rect1_translatex.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0.0,0.0 L 0.2 0 C 0.3958333333336,0.0 0.474845090492,0.206797621729 0.5916666666664,0.417082932942 C 0.7151610251224,0.639379624869 0.81625,0.974556908664 1.0,1.0 " /> + diff --git a/library/main/res/interpolator/progress_indeterminate_horizontal_rect2_scalex.xml b/library/main/res/interpolator/progress_indeterminate_horizontal_rect2_scalex.xml new file mode 100644 index 0000000..0ca9752 --- /dev/null +++ b/library/main/res/interpolator/progress_indeterminate_horizontal_rect2_scalex.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0,0 C 0.06834272400867,0.01992566661414 0.19220331656133,0.15855429260523 0.33333333333333,0.34926160892842 C 0.38410433133433,0.41477913453861 0.54945792615267,0.68136029463551 0.66666666666667,0.68279962777002 C 0.752586273196,0.68179620963216 0.737253971954,0.878896194318 1,1" />
\ No newline at end of file diff --git a/library/main/res/interpolator/progress_indeterminate_horizontal_rect2_translatex.xml b/library/main/res/interpolator/progress_indeterminate_horizontal_rect2_translatex.xml new file mode 100644 index 0000000..f663796 --- /dev/null +++ b/library/main/res/interpolator/progress_indeterminate_horizontal_rect2_translatex.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0.0,0.0 C 0.0375,0.0 0.128764607715,0.0895380946618 0.25,0.218553507947 C 0.322410320025,0.295610602487 0.436666666667,0.417591408114 0.483333333333,0.489826169306 C 0.69,0.80972296795 0.793333333333,0.950016125212 1.0,1.0 " />
\ No newline at end of file diff --git a/library/main/res/layout/car_setup_wizard_toolbar.xml b/library/main/res/layout/car_setup_wizard_toolbar.xml index d28a616..5c5703b 100644 --- a/library/main/res/layout/car_setup_wizard_toolbar.xml +++ b/library/main/res/layout/car_setup_wizard_toolbar.xml @@ -18,10 +18,8 @@ standard Car Toolbar/Application Bar, it doesn't require the same functionality, so it doesn't extend it. --> -<!-- Note: This layout needs a background in order for elevation to show up. --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:background="?attr/android:windowBackground" android:layout_width="match_parent" android:layout_height="@dimen/car_app_bar_height"> @@ -75,12 +73,23 @@ android:layout="@layout/primary_button"/> </LinearLayout> + <ImageView + android:id="@+id/divider" + android:layout_width="match_parent" + android:layout_height="2dp" + android:background="@color/car_suw_tint" + android:layout_above="@id/progress_bar" + android:layout_alignWithParentIfMissing="true"/> + <ProgressBar android:id="@+id/progress_bar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="2dp" + android:minHeight="0dp" + android:maxHeight="20dp" android:layout_alignParentBottom="true" + android:indeterminateDrawable="@drawable/progress_indeterminate_horizontal_material_trimmed" android:indeterminateTint="?android:attr/colorAccent" android:indeterminateTintMode="src_in"/> </RelativeLayout> diff --git a/library/main/src/com/android/car/setupwizardlib/BaseActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseActivity.java index 42137df..4fe59e7 100644 --- a/library/main/src/com/android/car/setupwizardlib/BaseActivity.java +++ b/library/main/src/com/android/car/setupwizardlib/BaseActivity.java @@ -458,20 +458,6 @@ public class BaseActivity extends FragmentActivity { } /** - * Adds elevation to the title bar in order to produce a drop shadow. - */ - protected void addElevationToTitleBar(boolean animate) { - mCarSetupWizardLayout.addElevationToTitleBar(animate); - } - - /** - * Removes the elevation from the title bar using an animation. - */ - protected void removeElevationFromTitleBar(boolean animate) { - mCarSetupWizardLayout.removeElevationFromTitleBar(animate); - } - - /** * Sets whether the progress bar is visible. */ protected void setProgressBarVisible(boolean visible) { diff --git a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java index 910f37e..cbf47f1 100644 --- a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java +++ b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java @@ -111,7 +111,7 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { protected void onStart() { super.onStart(); // Must be done here so that the SystemUI is hidden when back button is clicked - CarSetupWizardUiUtils.maybeHideSystemUI(this); + CarSetupWizardUiUtils.hideSystemUI(this); // Fragment commits are not allowed once the Activity's state has been saved. Once // onStart() has been called, the FragmentManager should now allow commits. mAllowFragmentCommits = true; @@ -156,7 +156,7 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { - CarSetupWizardUiUtils.maybeHideSystemUI(this); + CarSetupWizardUiUtils.hideSystemUI(this); } } @@ -266,21 +266,14 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { * Moves to the next Activity in the SetupWizard flow, and save the intent data. */ protected void nextAction(int resultCode, Intent data) { - if (resultCode == RESULT_CANCELED) { - throw new IllegalArgumentException("Cannot call nextAction with RESULT_CANCELED"); - } - setResultCode(resultCode, data); - if (mNextActionAlreadyTriggered) { - Log.v("CarSetupWizard", - "BaseSetupWizardActivity: nextAction triggered multiple times without" - + "page refresh, ignoring."); - return; - } - mNextActionAlreadyTriggered = true; - onNextActionInvoked(); - Intent nextIntent = - CarWizardManagerHelper.getNextIntent(getIntent(), mResultCode, mResultData); - startActivity(nextIntent); + launchNextAction(resultCode, data, /* forResult= */ false); + } + + /** + * Moves to the next Activity in the SetupWizard flow. Start next activity for result. + */ + protected void nextActionForResult(int resultCode) { + launchNextAction(resultCode, null, /* forResult= */ true); } /** @@ -463,26 +456,34 @@ abstract class BaseSetupWizardActivity extends FragmentActivity { } /** - * Adds elevation to the title bar in order to produce a drop shadow. - */ - protected void addElevationToTitleBar(boolean animate) { - mCarSetupWizardLayout.addElevationToTitleBar(animate); - } - - /** - * Removes the elevation from the title bar using an animation. - */ - protected void removeElevationFromTitleBar(boolean animate) { - mCarSetupWizardLayout.removeElevationFromTitleBar(animate); - } - - /** * Sets whether the progress bar is visible. */ protected void setProgressBarVisible(boolean visible) { mCarSetupWizardLayout.setProgressBarVisible(visible); } + private void launchNextAction(int resultCode, Intent data, boolean forResult) { + if (resultCode == RESULT_CANCELED) { + throw new IllegalArgumentException("Cannot call nextAction with RESULT_CANCELED"); + } + setResultCode(resultCode, data); + if (mNextActionAlreadyTriggered) { + Log.v("CarSetupWizard", + "BaseSetupWizardActivity: nextAction triggered multiple times without" + + "page refresh, ignoring."); + return; + } + mNextActionAlreadyTriggered = true; + onNextActionInvoked(); + Intent nextIntent = + CarWizardManagerHelper.getNextIntent(getIntent(), mResultCode, mResultData); + if (forResult) { + startActivityForResult(nextIntent, REQUEST_CODE_NEXT); + } else { + startActivity(nextIntent); + } + } + @VisibleForTesting boolean getAllowFragmentCommits() { return mAllowFragmentCommits; diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java index 1ef99bb..526a5ca 100644 --- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java +++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java @@ -16,9 +16,9 @@ package com.android.car.setupwizardlib; -import android.animation.ValueAnimator; import android.annotation.Nullable; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -59,11 +59,10 @@ import java.util.Objects; */ class CarSetupWizardBaseLayout extends LinearLayout { private static final String TAG = CarSetupWizardBaseLayout.class.getSimpleName(); - private static final int ANIMATION_DURATION_MS = 100; + private static final int INVALID_COLOR = 0; private View mBackButton; private View mTitleBar; - private Float mTitleBarElevation; private TextView mToolbarTitle; private PartnerConfigHelper mPartnerConfigHelper; @@ -82,6 +81,7 @@ class CarSetupWizardBaseLayout extends LinearLayout { private boolean mPrimaryToolbarButtonFlat; private View.OnClickListener mPrimaryToolbarButtonOnClick; private Button mSecondaryToolbarButton; + private ImageView mDivider; private ProgressBar mProgressBar; CarSetupWizardBaseLayout(Context context) { @@ -177,8 +177,6 @@ class CarSetupWizardBaseLayout extends LinearLayout { // Se the title bar. setTitleBar(findViewById(R.id.application_bar)); - mTitleBarElevation = - getContext().getResources().getDimension(R.dimen.title_bar_drop_shadow_elevation); int toolbarBgColor = mPartnerConfigHelper.getColor(getContext(), PartnerConfig.CONFIG_TOOLBAR_BG_COLOR); if (toolbarBgColor != 0) { @@ -218,6 +216,23 @@ class CarSetupWizardBaseLayout extends LinearLayout { mProgressBar = findViewById(R.id.progress_bar); setProgressBarVisible(showProgressBar); setProgressBarIndeterminate(indeterminateProgressBar); + int tintColor = mPartnerConfigHelper.getColor( + getContext(), + PartnerConfig.CONFIG_LOADING_INDICATOR_COLOR); + if (tintColor != INVALID_COLOR) { + mProgressBar.setIndeterminateTintList(ColorStateList.valueOf(tintColor)); + } + + float lineWeight = mPartnerConfigHelper.getDimension( + getContext(), + PartnerConfig.CONFIG_LOADING_INDICATOR_LINE_WEIGHT); + if (lineWeight > 0) { + ViewGroup.LayoutParams layoutParams = mProgressBar.getLayoutParams(); + layoutParams.height = Math.round(lineWeight); + mProgressBar.setLayoutParams(layoutParams); + } + + initDivider(); // Set orientation programmatically since the inflated layout uses <merge> setOrientation(LinearLayout.VERTICAL); @@ -518,48 +533,6 @@ class CarSetupWizardBaseLayout extends LinearLayout { } /** - * Adds elevation to the title bar in order to produce a drop shadow. An animation can be used - * in cases where a direct elevation changes would be too jarring. - * - * @param animate True when a smooth animation is wanted for the adding of the elevation. - */ - public void addElevationToTitleBar(boolean animate) { - if (animate) { - ValueAnimator elevationAnimator = - ValueAnimator.ofFloat(mTitleBar.getElevation(), mTitleBarElevation); - elevationAnimator - .setDuration(ANIMATION_DURATION_MS) - .addUpdateListener( - animation -> mTitleBar.setElevation( - (float) animation.getAnimatedValue())); - elevationAnimator.start(); - } else { - mTitleBar.setElevation(mTitleBarElevation); - } - } - - /** - * Removes the elevation from the title bar, an animation can be used in cases where a direct - * elevation changes would be too jarring. - * - * @param animate True when a smooth animation is wanted for the removal of the elevation. - */ - public void removeElevationFromTitleBar(boolean animate) { - if (animate) { - ValueAnimator elevationAnimator = - ValueAnimator.ofFloat(mTitleBar.getElevation(), 0f); - elevationAnimator - .setDuration(ANIMATION_DURATION_MS) - .addUpdateListener( - animation -> mTitleBar.setElevation( - (float) animation.getAnimatedValue())); - elevationAnimator.start(); - } else { - mTitleBar.setElevation(0f); - } - } - - /** * Sets the title bar view. */ private void setTitleBar(View titleBar) { @@ -714,6 +687,26 @@ class CarSetupWizardBaseLayout extends LinearLayout { setButtonTextColor(primaryButton, textColorConfig); } + private void initDivider() { + mDivider = findViewById(R.id.divider); + float dividerHeight = mPartnerConfigHelper.getDimension( + getContext(), + PartnerConfig.CONFIG_TOOLBAR_DIVIDER_LINE_WEIGHT); + if (dividerHeight >= 0) { + ViewGroup.LayoutParams layoutParams = mDivider.getLayoutParams(); + layoutParams.height = Math.round(dividerHeight); + mDivider.setLayoutParams(layoutParams); + } + if (dividerHeight > 0) { + Drawable dividerBg = mPartnerConfigHelper.getDrawable( + getContext(), + PartnerConfig.CONFIG_TOOLBAR_DIVIDER_BG); + if (dividerBg != null) { + mDivider.setBackground(dividerBg); + } + } + } + private GradientDrawable getGradientDrawable(Button button) { Drawable drawable = button.getBackground(); if (drawable instanceof InsetDrawable) { @@ -732,6 +725,9 @@ class CarSetupWizardBaseLayout extends LinearLayout { } private GradientDrawable getGradientDrawableFromInsetDrawable(InsetDrawable insetDrawable) { - return (GradientDrawable) insetDrawable.getDrawable(); + if (insetDrawable.getDrawable() instanceof GradientDrawable) { + return (GradientDrawable) insetDrawable.getDrawable(); + } + return null; } } diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java index 45cf62f..62e52d9 100644 --- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java +++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java @@ -18,7 +18,6 @@ package com.android.car.setupwizardlib; import android.annotation.Nullable; import android.content.Context; -import android.content.res.ColorStateList; import android.util.AttributeSet; import com.android.car.setupwizardlib.partner.PartnerConfig; @@ -56,12 +55,5 @@ public class CarSetupWizardDesignLayout extends CarSetupWizardBaseLayout { if (bgColor != 0) { setBackgroundColor(bgColor); } - - int tintColor = partnerConfigHelper.getColor( - context, - PartnerConfig.CONFIG_LOADING_INDICATOR_COLOR); - if (tintColor != 0) { - getProgressBar().setIndeterminateTintList(ColorStateList.valueOf(tintColor)); - } } } diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java index 554762f..9d30220 100644 --- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java +++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java @@ -15,7 +15,6 @@ */ package com.android.car.setupwizardlib; -import android.animation.ValueAnimator; import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; @@ -61,11 +60,9 @@ import java.util.Objects; @Deprecated public class CarSetupWizardLayout extends LinearLayout { private static final String TAG = CarSetupWizardLayout.class.getSimpleName(); - private static final int ANIMATION_DURATION_MS = 100; private View mBackButton; private View mTitleBar; - private Float mTitleBarElevation; private TextView mToolbarTitle; private PartnerConfigHelper mPartnerConfigHelper; @@ -178,8 +175,6 @@ public class CarSetupWizardLayout extends LinearLayout { // Se the title bar. setTitleBar(findViewById(R.id.application_bar)); - mTitleBarElevation = - getContext().getResources().getDimension(R.dimen.title_bar_drop_shadow_elevation); int toolbarBgColor = mPartnerConfigHelper.getColor(getContext(), PartnerConfig.CONFIG_TOOLBAR_BG_COLOR); if (toolbarBgColor != 0) { @@ -535,48 +530,6 @@ public class CarSetupWizardLayout extends LinearLayout { } /** - * Adds elevation to the title bar in order to produce a drop shadow. An animation can be used - * in cases where a direct elevation changes would be too jarring. - * - * @param animate True when a smooth animation is wanted for the adding of the elevation. - */ - public void addElevationToTitleBar(boolean animate) { - if (animate) { - ValueAnimator elevationAnimator = - ValueAnimator.ofFloat(mTitleBar.getElevation(), mTitleBarElevation); - elevationAnimator - .setDuration(ANIMATION_DURATION_MS) - .addUpdateListener( - animation -> mTitleBar.setElevation( - (float) animation.getAnimatedValue())); - elevationAnimator.start(); - } else { - mTitleBar.setElevation(mTitleBarElevation); - } - } - - /** - * Removes the elevation from the title bar, an animation can be used in cases where a direct - * elevation changes would be too jarring. - * - * @param animate True when a smooth animation is wanted for the removal of the elevation. - */ - public void removeElevationFromTitleBar(boolean animate) { - if (animate) { - ValueAnimator elevationAnimator = - ValueAnimator.ofFloat(mTitleBar.getElevation(), 0f); - elevationAnimator - .setDuration(ANIMATION_DURATION_MS) - .addUpdateListener( - animation -> mTitleBar.setElevation( - (float) animation.getAnimatedValue())); - elevationAnimator.start(); - } else { - mTitleBar.setElevation(0f); - } - } - - /** * Sets the title bar view. */ private void setTitleBar(View titleBar) { diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java index d3f6ea2..8946b7a 100644 --- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java +++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java @@ -19,9 +19,6 @@ package com.android.car.setupwizardlib.partner; /** Resources that can be customized by partner overlay APK. */ public enum PartnerConfig { - CONFIG_IS_IMMERSIVE( - PartnerConfigKey.KEY_IS_IMMERSIVE, ResourceType.BOOLEAN), - CONFIG_TOOLBAR_BG_COLOR( PartnerConfigKey.KEY_TOOLBAR_BG_COLOR, ResourceType.COLOR), @@ -64,9 +61,18 @@ public enum PartnerConfig { CONFIG_TOOLBAR_SECONDARY_BUTTON_TEXT_COLOR( PartnerConfigKey.KEY_TOOLBAR_SECONDARY_BUTTON_TEXT_COLOR, ResourceType.COLOR), + CONFIG_TOOLBAR_DIVIDER_BG( + PartnerConfigKey.KEY_TOOLBAR_DIVIDER_BG, ResourceType.DRAWABLE), + + CONFIG_TOOLBAR_DIVIDER_LINE_WEIGHT( + PartnerConfigKey.KEY_TOOLBAR_DIVIDER_LINE_WEIGHT, ResourceType.DIMENSION), + CONFIG_LOADING_INDICATOR_COLOR( PartnerConfigKey.KEY_LOADING_INDICATOR_COLOR, ResourceType.COLOR), + CONFIG_LOADING_INDICATOR_LINE_WEIGHT( + PartnerConfigKey.KEY_LOADING_INDICATOR_LINE_WEIGHT, ResourceType.DIMENSION), + CONFIG_LAYOUT_BG_COLOR( PartnerConfigKey.KEY_LAYOUT_BG_COLOR, ResourceType.COLOR); diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java index e98a533..de4aa9e 100644 --- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java +++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java @@ -23,7 +23,6 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.SOURCE) @StringDef({ - PartnerConfigKey.KEY_IS_IMMERSIVE, PartnerConfigKey.KEY_TOOLBAR_BG_COLOR, PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_BACK, PartnerConfigKey.KEY_TOOLBAR_BUTTON_FONT_FAMILY, @@ -38,15 +37,16 @@ import java.lang.annotation.RetentionPolicy; PartnerConfigKey.KEY_TOOLBAR_SECONDARY_BUTTON_BG, PartnerConfigKey.KEY_TOOLBAR_SECONDARY_BUTTON_BG_COLOR, PartnerConfigKey.KEY_TOOLBAR_SECONDARY_BUTTON_TEXT_COLOR, + PartnerConfigKey.KEY_TOOLBAR_DIVIDER_BG, + PartnerConfigKey.KEY_TOOLBAR_DIVIDER_LINE_WEIGHT, PartnerConfigKey.KEY_LOADING_INDICATOR_COLOR, + PartnerConfigKey.KEY_LOADING_INDICATOR_LINE_WEIGHT, PartnerConfigKey.KEY_LAYOUT_BG_COLOR }) /** Resource names that can be customized by partner overlay APK. */ public @interface PartnerConfigKey { - String KEY_IS_IMMERSIVE = "suw_compat_is_immersive"; - String KEY_TOOLBAR_BG_COLOR = "suw_compat_toolbar_bg_color"; String KEY_TOOLBAR_BUTTON_ICON_BACK = "suw_compat_toolbar_button_icon_back"; @@ -77,7 +77,13 @@ public @interface PartnerConfigKey { String KEY_TOOLBAR_SECONDARY_BUTTON_TEXT_COLOR = "suw_compat_toolbar_secondary_button_text_color"; - String KEY_LOADING_INDICATOR_COLOR = "suw_design_loading_indicator_color"; + String KEY_TOOLBAR_DIVIDER_BG = "suw_compat_toolbar_divider_bg"; + + String KEY_TOOLBAR_DIVIDER_LINE_WEIGHT = "suw_compat_toolbar_divider_line_weight"; + + String KEY_LOADING_INDICATOR_COLOR = "suw_compat_loading_indicator_color"; + + String KEY_LOADING_INDICATOR_LINE_WEIGHT = "suw_compat_loading_indicator_line_weight"; String KEY_LAYOUT_BG_COLOR = "suw_design_layout_bg_color"; } diff --git a/library/main/src/com/android/car/setupwizardlib/summary/DeferredAction.java b/library/main/src/com/android/car/setupwizardlib/summary/DeferredAction.java new file mode 100644 index 0000000..3add5be --- /dev/null +++ b/library/main/src/com/android/car/setupwizardlib/summary/DeferredAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.car.setupwizardlib.summary; + +/** + * An instance of a summary action's deferred state. This includes the deferred notification + * description and the completion state. + */ +public class DeferredAction implements Comparable<DeferredAction> { + + public final String deferredNotificationDescription; + public final boolean completed; + public final int priority; + + public DeferredAction(String deferredNotificationDescription, boolean completed, int priority) { + this.deferredNotificationDescription = deferredNotificationDescription; + this.completed = completed; + this.priority = priority; + } + + @Override + public int compareTo(DeferredAction o) { + if (o == null) { + return 1; + } + return priority - o.priority; + } +} diff --git a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java new file mode 100644 index 0000000..f0cc786 --- /dev/null +++ b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2019 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.car.setupwizardlib.summary; + +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Collects the actions provided by partners and compiles them into a list of {@link SummaryAction} + * items. + */ +public class PartnerSummaryActionsCollector { + + private static final String TAG = "PartnerSummaryActionsCollector"; + + private static final String CONTENT_PROVIDER_INTENT_ACTION = + "com.google.android.car.setupwizard.SETUP_ACTIONS_STATE_PROVIDER"; + + // Methods for fetching info from the content provider. + private static final String METHOD_GET_ACTION_COMPLETION_STATE = "get_action_completion_state"; + private static final String METHOD_GET_ACTION_SUMMARY_STATE = "get_action_summary_state"; + private static final String METHOD_GET_DEFERRED_ACTION_STATE = + "get_deferred_action_state"; + private static final String METHOD_GET_SUMMARY_ACTIONS = "get_summary_actions"; + + // Constants for fetching information from the bundles passed back by the content provider. + private static final String EXTRA_SUMMARY_ACTIONS_LIST = "summary_actions_list"; + private static final String EXTRA_IS_ACTION_COMPLETED = "is_action_completed"; + + // Constants for information contained within the summary action bundle. + private static final String EXTRA_SUMMARY_ACTION_HAS_DEPENDENCY = + "summary_action_has_dependency"; + private static final String EXTRA_SUMMARY_ACTION_DEPENDENCY_DESCRIPTION = + "summary_action_dependency_description"; + private static final String EXTRA_SUMMARY_ACTION_TITLE = "summary_action_title"; + private static final String EXTRA_SUMMARY_ACTION_DESCRIPTION = "summary_action_description"; + private static final String EXTRA_SUMMARY_ACTION_REQUIRES_NETWORK = + "summary_action_requires_network"; + private static final String EXTRA_SUMMARY_ACTION_WIZARD_SCRIPT = "summary_action_wizard_script"; + private static final String EXTRA_SUMMARY_ACTION_PRIORITY = "summary_action_priority"; + private static final String EXTRA_SUMMARY_ICON_RESOURCE_NAME = + "summary_action_icon_resource_name"; + private static final String EXTRA_SUMMARY_COMPLETED_DESCRIPTION = + "summary_action_completed_description"; + private static final String EXTRA_SUMMARY_ACTION_DEFERRED_NOTIFICATION_DESCRIPTION = + "summary_action_deferred_notification_description"; + + // Extra used as a key for the action id passed in to query summary action state. + private static final String EXTRA_ACTION_ID = "action_id"; + private static PartnerSummaryActionsCollector sPartnerSummaryActionsCollector; + private final Context mContext; + private Uri mContentProviderUri; + + /** private constructor, should use getter. */ + private PartnerSummaryActionsCollector(Context context) { + mContext = context; + ResolveInfo resolveInfo = getSummaryContentProviderResolveInfo(context.getPackageManager()); + + if (resolveInfo == null) { + Log.e(TAG, "Could not find partner content provider, ignoring partner summary items."); + return; + } + + mContentProviderUri = getSummaryContentProviderUri(resolveInfo); + + if (mContentProviderUri == null) { + Log.e(TAG, "Could not fetch content provider URI, ignoring partner summary items."); + } + } + + /** Gets the current instance of the {@link PartnerSummaryActionsCollector}. */ + public static PartnerSummaryActionsCollector get(Context context) { + if (sPartnerSummaryActionsCollector == null) { + sPartnerSummaryActionsCollector = new PartnerSummaryActionsCollector(context); + } + return sPartnerSummaryActionsCollector; + } + + /** + * Creates a summary action using the passed in completion state and summary state {@link + * Bundle}. + * This will pull out all relevant state such as title, description, dependencies, and anything + * else that defines a summary item. Returns null if the bundle does not have all the required + * state or is null. + */ + @Nullable + private static SummaryAction buildSummaryAction( + boolean completed, Bundle summaryStateBundle) { + if (summaryStateBundle == null) { + return null; + } + + String title = summaryStateBundle.getString(EXTRA_SUMMARY_ACTION_TITLE); + if (title == null) { + Log.e(TAG, "No title provided in summaryStateBundle: " + summaryStateBundle); + return null; + } + + String scriptUri = summaryStateBundle.getString(EXTRA_SUMMARY_ACTION_WIZARD_SCRIPT); + if (scriptUri == null) { + Log.e(TAG, "No wizard script provided in summaryStateBundle: " + summaryStateBundle); + return null; + } + + String description = summaryStateBundle.getString(EXTRA_SUMMARY_ACTION_DESCRIPTION, ""); + boolean requiresNetwork = + summaryStateBundle.getBoolean(EXTRA_SUMMARY_ACTION_REQUIRES_NETWORK, false); + boolean hasUnfinishedDependency = + summaryStateBundle.getBoolean(EXTRA_SUMMARY_ACTION_HAS_DEPENDENCY, false); + String unfinishedDependencyDescription = null; + if (hasUnfinishedDependency) { + unfinishedDependencyDescription = + summaryStateBundle.getString(EXTRA_SUMMARY_ACTION_DEPENDENCY_DESCRIPTION); + } + // Fetch priority, default 0 so that if no priority is provided they will be placed above + // the Google items which are located in 100-200. + int priority = summaryStateBundle.getInt(EXTRA_SUMMARY_ACTION_PRIORITY, 0); + String iconResourceName = null; + if (summaryStateBundle.containsKey(EXTRA_SUMMARY_ICON_RESOURCE_NAME)) { + iconResourceName = summaryStateBundle.getString(EXTRA_SUMMARY_ICON_RESOURCE_NAME, ""); + } + + String completedDescription = + summaryStateBundle.getString(EXTRA_SUMMARY_COMPLETED_DESCRIPTION, description); + return new SummaryAction( + title, + description, + requiresNetwork, + completed, + priority, + scriptUri, + hasUnfinishedDependency, + unfinishedDependencyDescription, + iconResourceName, + completedDescription); + } + + /** + * Creates a {@link DeferredAction} based on the passed in completion state and deferred action + * state bundle. Will return null if there is no notification description or a null bundle. + */ + private static DeferredAction buildDeferredAction(boolean completed, + Bundle deferredActionState) { + if (deferredActionState == null) { + Log.e(TAG, "Cannot build deferred action with null deferredActionState"); + return null; + } + + String deferredNotificationDescription = deferredActionState.getString( + EXTRA_SUMMARY_ACTION_DEFERRED_NOTIFICATION_DESCRIPTION); + if (deferredNotificationDescription == null) { + Log.v(TAG, "Cannot build deferred action with no notification description"); + return null; + } + + int priority = deferredActionState.getInt(EXTRA_SUMMARY_ACTION_PRIORITY, 0); + return new DeferredAction(deferredNotificationDescription, completed, priority); + } + + private static ResolveInfo getSummaryContentProviderResolveInfo(PackageManager packageManager) { + Intent contentProviderQueryIntent = new Intent(CONTENT_PROVIDER_INTENT_ACTION); + List<ResolveInfo> queryResults = + packageManager.queryIntentContentProviders(contentProviderQueryIntent, 0); + Log.v(TAG, "Query results size before pruning for system packages: " + queryResults.size()); + queryResults = + queryResults.stream() + .filter( + resolveInfo -> + resolveInfo.providerInfo != null + && resolveInfo.providerInfo.applicationInfo != null + && (resolveInfo.providerInfo.applicationInfo.flags + & ApplicationInfo.FLAG_SYSTEM) + != 0) + .collect(Collectors.toList()); + if (queryResults.size() > 1 || queryResults.isEmpty()) { + Log.v( + TAG, + "Found " + + queryResults.size() + + " content providers, there should be exactly 1 to show partner " + + "actions. Ignoring" + + " all partner actions."); + return null; + } + return queryResults.get(0); + } + + private static Uri getSummaryContentProviderUri(ResolveInfo resolveInfo) { + if (resolveInfo.providerInfo == null || TextUtils.isEmpty( + resolveInfo.providerInfo.authority)) { + Log.e(TAG, "Incorrectly configured partner content provider"); + return null; + } + return new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(resolveInfo.providerInfo.authority) + .build(); + } + + /** + * Gets the list of provided partner summary actions. Will return an empty list if none are + * found or there is an error loading them. + */ + public List<SummaryAction> getPartnerSummaryActions() { + if (mContentProviderUri == null) { + Log.e(TAG, "No content provider URI found, summary actions ignored"); + return new ArrayList<>(); + } + ArrayList<String> partnerSummaryActions; + try { + partnerSummaryActions = getPartnerSummaryActionsFromContentProvider( + mContentProviderUri); + } catch (NullPointerException | IllegalArgumentException e) { + Log.e(TAG, "Unable to find or successfully query content provider, ignoring action", e); + return new ArrayList<>(); + } + + if (partnerSummaryActions == null || partnerSummaryActions.isEmpty()) { + Log.v(TAG, "No actions were fetched for partners"); + return new ArrayList<>(); + } + + List<SummaryAction> summaryActionList = new ArrayList<>(); + for (String actionId : partnerSummaryActions) { + Log.v(TAG, "Attempting to generate summary action for id: " + actionId); + try { + boolean completed = + getActionCompletionStateFromContentProvider(actionId, mContentProviderUri); + Bundle summaryActionBundle = + getActionSummaryStateFromContentProvider(actionId, mContentProviderUri); + SummaryAction summaryAction = buildSummaryAction(completed, summaryActionBundle); + if (summaryAction != null) { + summaryActionList.add(summaryAction); + } + } catch (NullPointerException | IllegalArgumentException e) { + Log.e( + TAG, + "Unable to load the completion or config state for summary action: " + + actionId, + e); + } + } + return summaryActionList; + } + + /** Returns the set of partner deferred actions provided by the partner content provider. */ + public List<DeferredAction> getPartnerDeferredActions() { + if (mContentProviderUri == null) { + Log.e(TAG, "No content provider URI found, deferred actions ignored"); + return new ArrayList<>(); + } + + ArrayList<String> partnerSummaryActions; + try { + partnerSummaryActions = getPartnerSummaryActionsFromContentProvider( + mContentProviderUri); + } catch (NullPointerException | IllegalArgumentException e) { + Log.e(TAG, "Unable to find or successfully query content provider, ignoring action", e); + return new ArrayList<>(); + } + + if (partnerSummaryActions == null || partnerSummaryActions.isEmpty()) { + Log.v(TAG, "No actions were fetched for partners"); + return new ArrayList<>(); + } + + List<DeferredAction> deferredActions = new ArrayList<>(); + for (String actionId : partnerSummaryActions) { + Log.v(TAG, "Attempting to generate deferred action for id: " + actionId); + try { + boolean completed = + getActionCompletionStateFromContentProvider(actionId, mContentProviderUri); + Bundle deferredActionBundle = + getDeferredActionStateFromContentProvider(actionId, mContentProviderUri); + if (deferredActionBundle == null) { + Log.v(TAG, "No valid deferredActionBundle for action: " + actionId); + continue; + } + DeferredAction deferredAction = buildDeferredAction(completed, + deferredActionBundle); + if (deferredAction != null) { + deferredActions.add(deferredAction); + } + } catch (NullPointerException e) { + Log.e( + TAG, + "Unable to load the completion or config state for deferred action: " + + actionId, + e); + } + } + return deferredActions; + } + + /** + * Gets the list of actionId's for the partner summary actions form the passed in content + * provider + * {@link Uri}. + * + * @throws NullPointerException if the method is null on the content provider. + * @throws IllegalArgumentException if uri is not known or the request method is not supported + * properly. + */ + private ArrayList<String> getPartnerSummaryActionsFromContentProvider(Uri contentProviderUri) { + Bundle result = mContext.getContentResolver().call( + contentProviderUri, + METHOD_GET_SUMMARY_ACTIONS, + /* arg= */ null, + /* extras= */ null); + if (result == null || result.getStringArrayList(EXTRA_SUMMARY_ACTIONS_LIST) == null) { + Log.e( + TAG, + "No summary actions returned from content resolve call, can't fetch partner " + + "actions."); + throw new IllegalArgumentException( + "Uri: " + contentProviderUri + " did not return a list of actionId's."); + } + return result.getStringArrayList(EXTRA_SUMMARY_ACTIONS_LIST); + } + + /** + * Gets the completion state for the specific actionId passed in using the passed in content + * provider {@link Uri}. + * + * @throws NullPointerException if the method is null on the content provider. + * @throws IllegalArgumentException if uri is not known or the request method is not supported + * properly. + */ + private boolean getActionCompletionStateFromContentProvider( + String actionId, Uri contentProviderUri) { + Bundle completionStateArgs = new Bundle(); + completionStateArgs.putString(EXTRA_ACTION_ID, actionId); + Bundle result = mContext.getContentResolver().call( + contentProviderUri, + METHOD_GET_ACTION_COMPLETION_STATE, + /* arg= */ null, + completionStateArgs); + if (result == null || !result.containsKey(EXTRA_IS_ACTION_COMPLETED)) { + throw new IllegalArgumentException( + "No action with id " + actionId + " found in content provider"); + } + return result.getBoolean(EXTRA_IS_ACTION_COMPLETED, true); + } + + private Bundle getActionSummaryStateFromContentProvider(String actionId, + Uri contentProviderUri) { + Bundle summaryStateArgs = new Bundle(); + summaryStateArgs.putString(EXTRA_ACTION_ID, actionId); + Bundle result = mContext.getContentResolver().call( + contentProviderUri, + METHOD_GET_ACTION_SUMMARY_STATE, + /* arg= */ null, + summaryStateArgs); + if (result == null) { + throw new IllegalArgumentException( + "No action summary found in content provider for " + actionId); + } + return result; + } + + private Bundle getDeferredActionStateFromContentProvider(String actionId, + Uri contentProviderUri) { + Bundle deferredStateArgs = new Bundle(); + deferredStateArgs.putString(EXTRA_ACTION_ID, actionId); + Bundle result; + try { + result = mContext.getContentResolver().call( + contentProviderUri, + METHOD_GET_DEFERRED_ACTION_STATE, + /* arg= */ null, + deferredStateArgs); + } catch (UnsupportedOperationException e) { + Log.v(TAG, "Deferred notification query not supported by partner content provider"); + return null; + } + return result; + } +} diff --git a/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java b/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java new file mode 100644 index 0000000..aac4ce7 --- /dev/null +++ b/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 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.car.setupwizardlib.summary; + +import android.annotation.NonNull; + +/** An instance that represents a single summary action item and all of its state. */ +public class SummaryAction implements Comparable<SummaryAction> { + + public final String actionTitle; + public final String actionDescription; + public final boolean requiresNetwork; + public final String scriptUri; + public final int priority; + public final boolean hasUnfinishedDependency; + public final String dependencyDescription; + public final boolean completed; + public final String iconResourceName; + public final String completedDescription; + + public SummaryAction( + String actionTitle, + String actionDescription, + boolean requiresNetwork, + boolean completed, + int priority, + String scriptUri, + boolean hasUnfinishedDependency, + String dependencyDescription, + String iconResourceName, + String completedDescription) { + this.actionTitle = actionTitle; + this.actionDescription = actionDescription; + this.requiresNetwork = requiresNetwork; + this.completed = completed; + this.priority = priority; + this.scriptUri = scriptUri; + this.hasUnfinishedDependency = hasUnfinishedDependency; + this.dependencyDescription = dependencyDescription; + this.iconResourceName = iconResourceName; + this.completedDescription = completedDescription; + } + + @Override + public int compareTo(@NonNull SummaryAction o) { + if (o == null) { + return 1; + } + return priority - o.priority; + } +} diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java b/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java index 5408aa1..126f7e0 100644 --- a/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java +++ b/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java @@ -18,8 +18,12 @@ package com.android.car.setupwizardlib.util; import android.car.Car; import android.car.CarNotConnectedException; +import android.car.VehicleAreaType; +import android.car.VehiclePropertyIds; import android.car.drivingstate.CarUxRestrictions; import android.car.drivingstate.CarUxRestrictionsManager; +import android.car.hardware.CarPropertyValue; +import android.car.hardware.property.CarPropertyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -42,11 +46,17 @@ public class CarDrivingStateMonitor implements public static final String EXIT_BROADCAST_ACTION = "com.android.car.setupwizardlib.driving_exit"; + public static final String INTENT_EXTRA_REASON = "reason"; + public static final String REASON_GEAR_REVERSAL = "gear_reversal"; + private static final String TAG = "CarDrivingStateMonitor"; private static final long DISCONNECT_DELAY_MS = 700; + private static final int GEAR_REVERSE = 2; + private Car mCar; private CarUxRestrictionsManager mRestrictionsManager; + private CarPropertyManager mCarPropertyManager; // Need to track the number of times the monitor is started so a single stopMonitor call does // not override them all. private int mMonitorStartedCount; @@ -60,6 +70,25 @@ public class CarDrivingStateMonitor implements @VisibleForTesting final Runnable mDisconnectRunnable = this::disconnectCarMonitor; + private final CarPropertyManager.CarPropertyEventCallback mGearChangeCallback = + new CarPropertyManager.CarPropertyEventCallback() { + @SuppressWarnings("rawtypes") + @Override + public void onChangeEvent(CarPropertyValue value) { + switch (value.getPropertyId()) { + case VehiclePropertyIds.GEAR_SELECTION: + if ((Integer) value.getValue() == GEAR_REVERSE) { + Log.v(TAG, "Gear has reversed, exiting SetupWizard."); + broadcastGearReversal(); + } + break; + } + } + + @Override + public void onErrorEvent(int propertyId, int zone) {} + }; + private CarDrivingStateMonitor(Context context) { mContext = context.getApplicationContext(); } @@ -107,18 +136,9 @@ public class CarDrivingStateMonitor implements @Override public void onServiceConnected(ComponentName name, IBinder service) { try { - mRestrictionsManager = (CarUxRestrictionsManager) - mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); - if (mRestrictionsManager == null) { - Log.e(TAG, "Unable to get CarUxRestrictionsManager"); - return; - } - onUxRestrictionsChanged(mRestrictionsManager.getCurrentCarUxRestrictions()); - mRestrictionsManager.registerListener(CarDrivingStateMonitor.this); - if (mStopMonitorAfterUxCheck) { - mStopMonitorAfterUxCheck = false; - stopMonitor(); - } + registerPropertyManager(); + registerRestrictionsManager(); + } catch (CarNotConnectedException e) { Log.e(TAG, "Car not connected", e); } @@ -179,6 +199,10 @@ public class CarDrivingStateMonitor implements mRestrictionsManager.unregisterListener(); mRestrictionsManager = null; } + if (mCarPropertyManager != null) { + mCarPropertyManager.unregisterCallback(mGearChangeCallback); + mCarPropertyManager = null; + } } catch (CarNotConnectedException e) { Log.e(TAG, "Car not connected for unregistering listener", e); } @@ -267,4 +291,50 @@ public class CarDrivingStateMonitor implements CarHelperRegistry.getRegistry(context).putHelper( CarDrivingStateMonitor.class, new CarDrivingStateMonitor(context)); } + + private void registerRestrictionsManager() { + mRestrictionsManager = (CarUxRestrictionsManager) + mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); + if (mRestrictionsManager == null) { + Log.e(TAG, "Unable to get CarUxRestrictionsManager"); + return; + } + onUxRestrictionsChanged(mRestrictionsManager.getCurrentCarUxRestrictions()); + mRestrictionsManager.registerListener(CarDrivingStateMonitor.this); + if (mStopMonitorAfterUxCheck) { + mStopMonitorAfterUxCheck = false; + stopMonitor(); + } + } + + private void registerPropertyManager() { + mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE); + if (mCarPropertyManager == null) { + Log.e(TAG, "Unable to get CarPropertyManager"); + return; + } + mCarPropertyManager.registerCallback( + mGearChangeCallback, VehiclePropertyIds.GEAR_SELECTION, + CarPropertyManager.SENSOR_RATE_ONCHANGE); + CarPropertyValue<Integer> gearSelection = + mCarPropertyManager.getProperty(Integer.class, VehiclePropertyIds.GEAR_SELECTION, + VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL); + if (gearSelection != null + && gearSelection.getStatus() == CarPropertyValue.STATUS_AVAILABLE) { + if (gearSelection.getValue() == GEAR_REVERSE) { + Log.v(TAG, "SetupWizard started when gear is in reverse, exiting."); + broadcastGearReversal(); + } + } else { + Log.e(TAG, "GEAR_SELECTION is not available."); + } + } + + private void broadcastGearReversal() { + Intent intent = new Intent(); + intent.setAction(EXIT_BROADCAST_ACTION); + intent.putExtra(INTENT_EXTRA_REASON, REASON_GEAR_REVERSAL); + mContext.sendBroadcast(intent); + } + } diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java b/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java index 5a87323..3af842a 100644 --- a/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java +++ b/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java @@ -17,33 +17,26 @@ package com.android.car.setupwizardlib.util; import android.app.Activity; -import android.util.Log; import android.view.View; import androidx.core.util.Preconditions; -import com.android.car.setupwizardlib.partner.PartnerConfig; -import com.android.car.setupwizardlib.partner.PartnerConfigHelper; - /** Utilities to aid in UI for car setup wizard flow. */ public final class CarSetupWizardUiUtils { private static final String TAG = CarSetupWizardUiUtils.class.getSimpleName(); - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); - /** Hide system UI if configured as such by partner */ + /** Hide system UI */ + public static void hideSystemUI(Activity activity) { + maybeHideSystemUI(activity); + } + + /** Hide system UI + * @deprecated Use {@code hideSystemUI} + **/ + @Deprecated public static void maybeHideSystemUI(Activity activity) { Preconditions.checkNotNull(activity); - if (!PartnerConfigHelper.get(activity) - .getBoolean(activity, PartnerConfig.CONFIG_IS_IMMERSIVE, true)) { - if (VERBOSE) { - Log.v(TAG, "Immersive mode disabled"); - } - return; - } - if (VERBOSE) { - Log.v(TAG, "Setting immersive mode for SystemUi"); - } // See https://developer.android.com/training/system-ui/immersive#EnableFullscreen // Enables regular immersive mode. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. diff --git a/library/main/tests/robotests/Android.bp b/library/main/tests/robotests/Android.bp deleted file mode 100644 index 13335f3..0000000 --- a/library/main/tests/robotests/Android.bp +++ /dev/null @@ -1,33 +0,0 @@ -//############################################################## -// CarSetupWizardLib app just for Robolectric test target. # -//############################################################## -android_app { - name: "CarSetupWizardLib", - - resource_dirs: ["res"], - - platform_apis: true, - - privileged: true, - - libs: ["android.car"], - - static_libs: ["car-setup-wizard-lib"], -} - -//############################################################## -// CarSetupWizardLib Robolectric test target. # -//############################################################## -android_robolectric_test { - name: "CarSetupWizardLibRoboTests", - - srcs: ["src/**/*.java"], - - java_resource_dirs: ["config"], - - libs: [ - "android.car", - ], - - instrumentation_for: "CarSetupWizardLib", -} diff --git a/library/main/tests/robotests/Android.mk b/library/main/tests/robotests/Android.mk new file mode 100644 index 0000000..1d62740 --- /dev/null +++ b/library/main/tests/robotests/Android.mk @@ -0,0 +1,75 @@ +LOCAL_PATH := $(call my-dir) + +############################################################### +# CarSetupWizardLib app just for Robolectric test target. # +############################################################### +include $(CLEAR_VARS) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := CarSetupWizardLib +LOCAL_PRIVATE_PLATFORM_APIS := true +LOCAL_MODULE_TAGS := optional + +LOCAL_USE_AAPT2 := true + +LOCAL_PRIVILEGED_MODULE := true + +LOCAL_JAVA_LIBRARIES := android.car + +LOCAL_STATIC_ANDROID_LIBRARIES += car-setup-wizard-lib + +include $(BUILD_PACKAGE) + +############################################################### +# CarSetupWizardLib Robolectric test target. # +############################################################### +include $(CLEAR_VARS) + +LOCAL_MODULE := CarSetupWizardLibRoboTests +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_JAVA_RESOURCE_DIRS := config + +LOCAL_JAVA_LIBRARIES := \ + android.car \ + robolectric_android-all-stub \ + Robolectric_all-target \ + mockito-robolectric-prebuilt \ + truth-prebuilt + +LOCAL_INSTRUMENTATION_FOR := CarSetupWizardLib + +LOCAL_MODULE_TAGS := optional + +# Generate test_config.properties +include external/robolectric-shadows/gen_test_config.mk + +include $(BUILD_STATIC_JAVA_LIBRARY) + +############################################################### +# CarSetupWizardLib runner target to run the previous target. # +############################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := RunCarSetupWizardLibRoboTests + +LOCAL_JAVA_LIBRARIES := \ + android.car \ + CarSetupWizardLibRoboTests \ + robolectric_android-all-stub \ + Robolectric_all-target \ + mockito-robolectric-prebuilt \ + truth-prebuilt + +LOCAL_TEST_PACKAGE := CarSetupWizardLib + +LOCAL_ROBOTEST_FILES := $(filter-out %/BaseRobolectricTest.java,\ + $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.)) + +LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src + +include external/robolectric-shadows/run_robotests.mk diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java index 2ec9db8..6ec0c28 100644 --- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java +++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java @@ -440,18 +440,6 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest { } @Test - public void testTitleBarElevationChange() { - mCarSetupWizardCompatLayout.addElevationToTitleBar(/*animate= */ false); - View titleBar = mCarSetupWizardCompatLayout.findViewById(R.id.application_bar); - assertThat(titleBar.getElevation()).isEqualTo( - application.getResources().getDimension( - R.dimen.title_bar_drop_shadow_elevation)); - - mCarSetupWizardCompatLayout.removeElevationFromTitleBar(/*animate= */ false); - assertThat(titleBar.getElevation()).isEqualTo(0f); - } - - @Test public void testPartnerResourcesAreApplied() { setupFakeContentProvider(); diff --git a/library/utils/Android.bp b/library/utils/Android.bp index ac1f514..f8cb4c7 100644 --- a/library/utils/Android.bp +++ b/library/utils/Android.bp @@ -15,8 +15,14 @@ android_library { name: "car-setup-wizard-lib-utils", - srcs: ["src/**/*.java", - "src/**/*.aidl"], + srcs: [ + "src/**/*.java", + "src/com/android/car/setupwizardlib/IInitialLockSetupService.aidl", + "src/com/android/car/setupwizardlib/InitialLockListener.java", + "src/com/android/car/setupwizardlib/InitialLockSetupClient.java", + "src/com/android/car/setupwizardlib/InitialLockSetupConstants.java", + "src/com/android/car/setupwizardlib/InitialLockSetupHelper.java", + ], libs: ["android.car"], optimize: { enabled: false, |