| /* | |
| * Copyright (C) 2021 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.managedprovisioning.provisioning; | |
| import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; | |
| import static com.google.android.setupdesign.util.ThemeHelper.shouldApplyMaterialYouStyle; | |
| import android.app.Activity; | |
| import android.content.Context; | |
| import android.text.Layout; | |
| import android.view.View; | |
| import android.view.ViewGroup; | |
| import android.widget.LinearLayout; | |
| import android.widget.Space; | |
| import android.widget.TextView; | |
| import androidx.annotation.StringRes; | |
| import com.android.managedprovisioning.R; | |
| import com.android.managedprovisioning.common.InitializeLayoutConsumerHandler; | |
| import com.android.managedprovisioning.common.StylerHelper; | |
| import com.android.managedprovisioning.common.Utils; | |
| import com.android.managedprovisioning.model.ProvisioningParams; | |
| import com.android.managedprovisioning.provisioning.ProvisioningActivity.ProvisioningMode; | |
| import com.android.managedprovisioning.provisioning.ProvisioningModeWrapperProvider.ProvisioningModeWrapper; | |
| import com.android.managedprovisioning.provisioning.TransitionAnimationHelper.AnimationComponents; | |
| import com.android.managedprovisioning.provisioning.TransitionAnimationHelper.TransitionAnimationCallback; | |
| import com.android.managedprovisioning.provisioning.TransitionAnimationHelper.TransitionAnimationStateManager; | |
| import com.airbnb.lottie.LottieAnimationView; | |
| import com.google.android.setupdesign.GlifLayout; | |
| import com.google.android.setupdesign.util.ContentStyler; | |
| import com.google.android.setupdesign.util.DescriptionStyler; | |
| import com.google.android.setupdesign.util.DeviceHelper; | |
| import com.google.auto.value.AutoValue; | |
| import java.util.function.Supplier; | |
| @AutoValue | |
| abstract class ProvisioningActivityBridgeImpl implements ProvisioningActivityBridge { | |
| private TransitionAnimationHelper mTransitionAnimationHelper; | |
| private ViewGroup mButtonFooterContainer; | |
| private Context mContext; | |
| abstract Utils getUtils(); | |
| abstract ProvisioningParams getParams(); | |
| abstract @ProvisioningMode int getProvisioningMode(); | |
| abstract ProvisioningManager getProvisioningManager(); | |
| abstract TransitionAnimationCallback getTransitionAnimationCallback(); | |
| abstract InitializeLayoutConsumerHandler getInitializeLayoutParamsConsumer(); | |
| abstract boolean getShouldSkipEducationScreens(); | |
| abstract @StringRes int getProgressLabelResId(); | |
| abstract ProvisioningActivityBridgeCallbacks getBridgeCallbacks(); | |
| abstract TransitionAnimationStateManager getStateManager(); | |
| @Override | |
| public void initiateUi(Activity activity) { | |
| Context context = activity.getApplicationContext(); | |
| CharSequence deviceName = DeviceHelper.getDeviceName(context); | |
| boolean isPoProvisioning = getUtils().isProfileOwnerAction(getParams().provisioningAction); | |
| String title = | |
| isPoProvisioning | |
| ? activity.getString(R.string.setup_profile_progress) | |
| : activity.getString(R.string.setup_device_progress, deviceName); | |
| int layoutResId = | |
| getShouldSkipEducationScreens() | |
| ? R.layout.empty_loading_layout | |
| : R.layout.provisioning_progress; | |
| getInitializeLayoutParamsConsumer() | |
| .initializeLayoutParams(layoutResId, /* headerResId */ null); | |
| activity.setTitle(title); | |
| GlifLayout layout = activity.findViewById(R.id.setup_wizard_layout); | |
| setupEducationViews(layout, activity, getShouldSkipEducationScreens(), | |
| getProgressLabelResId()); | |
| if (getUtils().isFinancedDeviceAction(getParams().provisioningAction)) { | |
| // make the icon invisible | |
| layout.findViewById(com.google.android.setupdesign.R.id.sud_layout_icon) | |
| .setVisibility(View.INVISIBLE); | |
| } | |
| Utils.addNextButton(layout, v -> getBridgeCallbacks().onNextButtonClicked()); | |
| // TODO(b/181323689): Add tests to ProvisioningActivityTest that the button is not | |
| // shown for non-DO provisioning flows. | |
| if (getUtils().isDeviceOwnerAction(getParams().provisioningAction)) { | |
| Utils.addAbortAndResetButton(layout, v -> getBridgeCallbacks().onAbortButtonClicked()); | |
| } | |
| ViewGroup root = activity.findViewById( | |
| com.google.android.setupdesign.R.id.sud_layout_template_content); | |
| mButtonFooterContainer = getButtonFooterContainer(root); | |
| mButtonFooterContainer.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); | |
| getUtils() | |
| .onViewMeasured( | |
| mButtonFooterContainer, | |
| view -> | |
| onContainerMeasured(view, activity, | |
| getBridgeCallbacks()::isProvisioningFinalized)); | |
| } | |
| private void onContainerMeasured( | |
| View view, | |
| Activity activity, | |
| Supplier<Boolean> checkIsProvisioningFinalised) { | |
| if (checkIsProvisioningFinalised.get()) { | |
| view.setVisibility(View.VISIBLE); | |
| return; | |
| } | |
| getProvisioningProgressLabelContainer(activity).setLayoutParams( | |
| new LinearLayout.LayoutParams( | |
| ViewGroup.LayoutParams.MATCH_PARENT, | |
| view.getHeight())); | |
| view.setVisibility(View.GONE); | |
| } | |
| @Override | |
| public void onStart(Activity activity) { | |
| if (!getShouldSkipEducationScreens()) { | |
| startTransitionAnimation(activity, getTransitionAnimationCallback()); | |
| } | |
| } | |
| @Override | |
| public void onStop() { | |
| if (!getShouldSkipEducationScreens()) { | |
| endTransitionAnimation(); | |
| } | |
| } | |
| @Override | |
| public void onProvisioningFinalized(Activity activity) { | |
| if (!getShouldSkipEducationScreens()) { | |
| getProvisioningProgressLabelContainer(activity).setVisibility(View.GONE); | |
| mButtonFooterContainer.setVisibility(View.VISIBLE); | |
| } | |
| if (getShouldSkipEducationScreens()) { | |
| getBridgeCallbacks().onNextButtonClicked(); | |
| } | |
| } | |
| @Override | |
| public boolean shouldShowButtonsWhenPreProvisioningCompletes() { | |
| return mTransitionAnimationHelper.areAllTransitionsShown(); | |
| } | |
| private void startTransitionAnimation( | |
| Activity activity, | |
| TransitionAnimationCallback callback) { | |
| final GlifLayout layout = activity.findViewById(R.id.setup_wizard_layout); | |
| setupTransitionAnimationHelper(layout, callback); | |
| mTransitionAnimationHelper.start(); | |
| } | |
| private void endTransitionAnimation() { | |
| mTransitionAnimationHelper.stop(); | |
| mTransitionAnimationHelper = null; | |
| } | |
| private void setupTransitionAnimationHelper( | |
| GlifLayout layout, TransitionAnimationCallback callback) { | |
| TextView header = layout.findViewById(com.google.android.setupdesign.R.id.suc_layout_title); | |
| TextView description = | |
| layout.findViewById(com.google.android.setupdesign.R.id.sud_layout_subtitle); | |
| // No hyphenation split word in header | |
| header.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); | |
| ViewGroup item1 = layout.findViewById(R.id.item1); | |
| ViewGroup item2 = layout.findViewById(R.id.item2); | |
| LottieAnimationView drawable = layout.findViewById(R.id.animation); | |
| ViewGroup drawableContainer = layout.findViewById(R.id.animation_container); | |
| Space space1 = layout.findViewById(R.id.space1); | |
| Space space2 = layout.findViewById(R.id.space2); | |
| AnimationComponents animationComponents = | |
| new AnimationComponents( | |
| header, description, item1, item2, drawable, drawableContainer, space1, | |
| space2); | |
| ProvisioningModeWrapperProvider provider = | |
| new ProvisioningModeWrapperProvider(getParams()); | |
| ProvisioningModeWrapper provisioningModeWrapper = | |
| provider.getProvisioningModeWrapper(getProvisioningMode(), | |
| DeviceHelper.getDeviceName(layout.getContext())); | |
| mTransitionAnimationHelper = | |
| new TransitionAnimationHelper( | |
| animationComponents, | |
| callback, | |
| getStateManager(), | |
| new StylerHelper(), | |
| provisioningModeWrapper); | |
| } | |
| private void setupEducationViews( | |
| GlifLayout layout, | |
| Activity activity, | |
| boolean shouldSkipEducationScreens, | |
| @StringRes int progressLabelResId) { | |
| addProvisioningProgressLabel(activity); | |
| if (shouldSkipEducationScreens) { | |
| TextView header = | |
| layout.findViewById(com.google.android.setupdesign.R.id.suc_layout_title); | |
| header.setText(progressLabelResId); | |
| getProvisioningProgressLabelContainer(activity).setVisibility(View.GONE); | |
| } else { | |
| setupProgressLabel(progressLabelResId, activity); | |
| } | |
| } | |
| private void addProvisioningProgressLabel(Activity activity) { | |
| ViewGroup parent = activity.findViewById( | |
| com.google.android.setupdesign.R.id.sud_layout_template_content); | |
| activity.getLayoutInflater().inflate(R.layout.label_provisioning_progress, parent, true); | |
| } | |
| private ViewGroup getProvisioningProgressLabelContainer(Activity activity) { | |
| ViewGroup parent = activity.findViewById( | |
| com.google.android.setupdesign.R.id.sud_layout_template_content); | |
| return parent.findViewById(R.id.provisioning_progress_container); | |
| } | |
| /** | |
| * Returns the relevant progress label and takes care of visibilities to show the correct one. | |
| */ | |
| private void setupProgressLabel(@StringRes int progressLabelResId, Activity activity) { | |
| TextView progressLabel = getRelevantProgressLabel(activity); | |
| DescriptionStyler.applyPartnerCustomizationHeavyStyle(progressLabel); | |
| progressLabel.setTextColor( | |
| shouldApplyMaterialYouStyle(activity) | |
| ? getUtils().getTextSecondaryColor(activity) | |
| : getUtils().getAccentColor(activity)); | |
| progressLabel.setText(progressLabelResId); | |
| int sidePadding = (int) ContentStyler.getPartnerContentMarginStart(activity); | |
| progressLabel.setPadding(sidePadding, /* top= */ 0, sidePadding, /* bottom= */ 0); | |
| getProvisioningProgressLabelContainer(activity).setVisibility(View.VISIBLE); | |
| } | |
| private TextView getRelevantProgressLabel(Activity activity) { | |
| ViewGroup parent = (ViewGroup) activity.findViewById( | |
| com.google.android.setupdesign.R.id.suc_layout_footer).getParent(); | |
| TextView provisioningProgressLabel = parent.findViewById(R.id.provisioning_progress); | |
| if (provisioningProgressLabel != null) { | |
| return provisioningProgressLabel; | |
| } | |
| TextView leftProgress = parent.findViewById(R.id.provisioning_progress_left); | |
| TextView rightProgress = parent.findViewById(R.id.provisioning_progress_right); | |
| if (activity.getResources().getBoolean(R.bool.show_progress_label_on_left_side)) { | |
| leftProgress.setVisibility(View.VISIBLE); | |
| rightProgress.setVisibility(View.INVISIBLE); | |
| return leftProgress; | |
| } | |
| leftProgress.setVisibility(View.INVISIBLE); | |
| rightProgress.setVisibility(View.VISIBLE); | |
| return rightProgress; | |
| } | |
| private ViewGroup getButtonFooterContainer(ViewGroup root) { | |
| return (ViewGroup) root.getChildAt(root.getChildCount() - 2); | |
| } | |
| static Builder builder() { | |
| return new AutoValue_ProvisioningActivityBridgeImpl.Builder(); | |
| } | |
| @AutoValue.Builder | |
| abstract static class Builder { | |
| abstract Builder setUtils(Utils utils); | |
| abstract Builder setParams(ProvisioningParams params); | |
| abstract Builder setProvisioningMode(@ProvisioningMode int provisioningMode); | |
| abstract Builder setProvisioningManager(ProvisioningManager provisioningManager); | |
| abstract Builder setTransitionAnimationCallback(TransitionAnimationCallback callback); | |
| abstract Builder setInitializeLayoutParamsConsumer( | |
| InitializeLayoutConsumerHandler initializeLayoutParamsConsumer); | |
| abstract Builder setShouldSkipEducationScreens(boolean shouldSkipEducationScreens); | |
| abstract Builder setProgressLabelResId(@StringRes int progressLabelResId); | |
| abstract Builder setBridgeCallbacks( | |
| ProvisioningActivityBridgeCallbacks callbacks); | |
| abstract Builder setStateManager(TransitionAnimationStateManager stateManager); | |
| abstract ProvisioningActivityBridgeImpl build(); | |
| } | |
| } |