/* * 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. */ package com.android.systemui.qs; import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; import android.content.Context; import android.content.res.Configuration; import android.database.ContentObserver; import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.systemui.FontSizeUtils; import com.android.systemui.res.R; /** * Footer of expanded Quick Settings, tiles page indicator, (optionally) build number and * {@link FooterActionsView} */ public class QSFooterView extends FrameLayout { private PageIndicator mPageIndicator; private TextView mBuildText; private View mEditButton; @Nullable protected TouchAnimator mFooterAnimator; private boolean mQsDisabled; private boolean mExpanded; private float mExpansionAmount; private boolean mShouldShowBuildText; @Nullable private OnClickListener mExpandClickListener; private final ContentObserver mDeveloperSettingsObserver = new ContentObserver( new Handler(mContext.getMainLooper())) { @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); setBuildText(); } }; public QSFooterView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onFinishInflate() { super.onFinishInflate(); mPageIndicator = findViewById(R.id.footer_page_indicator); mBuildText = findViewById(R.id.build); mEditButton = findViewById(android.R.id.edit); updateResources(); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); setBuildText(); } private void setBuildText() { if (mBuildText == null) return; if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)) { mBuildText.setText(mContext.getString( com.android.internal.R.string.bugreport_status, Build.VERSION.RELEASE_OR_CODENAME, Build.ID)); // Set as selected for marquee before its made visible, then it won't be announced when // it's made visible. mBuildText.setSelected(true); mShouldShowBuildText = true; } else { mBuildText.setText(null); mShouldShowBuildText = false; mBuildText.setSelected(false); } } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); updateResources(); } private void updateResources() { updateFooterAnimator(); updateEditButtonResources(); updateBuildTextResources(); MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); lp.height = getResources().getDimensionPixelSize(R.dimen.qs_footer_height); int sideMargin = getResources().getDimensionPixelSize(R.dimen.qs_footer_margin); lp.leftMargin = sideMargin; lp.rightMargin = sideMargin; lp.bottomMargin = getResources().getDimensionPixelSize(R.dimen.qs_footers_margin_bottom); setLayoutParams(lp); } private void updateEditButtonResources() { int size = getResources().getDimensionPixelSize(R.dimen.qs_footer_action_button_size); int padding = getResources().getDimensionPixelSize(R.dimen.qs_footer_icon_padding); MarginLayoutParams lp = (MarginLayoutParams) mEditButton.getLayoutParams(); lp.height = size; lp.width = size; mEditButton.setLayoutParams(lp); mEditButton.setPadding(padding, padding, padding, padding); } private void updateBuildTextResources() { FontSizeUtils.updateFontSizeFromStyle(mBuildText, R.style.TextAppearance_QS_Status_Build); } private void updateFooterAnimator() { mFooterAnimator = createFooterAnimator(); } @Nullable private TouchAnimator createFooterAnimator() { TouchAnimator.Builder builder = new TouchAnimator.Builder() .addFloat(mPageIndicator, "alpha", 0, 1) .addFloat(mBuildText, "alpha", 0, 1) .addFloat(mEditButton, "alpha", 0, 1) .setStartDelay(0.9f); return builder.build(); } /** */ public void setKeyguardShowing() { setExpansion(mExpansionAmount); } public void setExpandClickListener(OnClickListener onClickListener) { mExpandClickListener = onClickListener; } void setExpanded(boolean expanded) { if (mExpanded == expanded) return; mExpanded = expanded; updateEverything(); } /** */ public void setExpansion(float headerExpansionFraction) { mExpansionAmount = headerExpansionFraction; if (mFooterAnimator != null) { mFooterAnimator.setPosition(headerExpansionFraction); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED), false, mDeveloperSettingsObserver, UserHandle.USER_ALL); } @Override @VisibleForTesting public void onDetachedFromWindow() { mContext.getContentResolver().unregisterContentObserver(mDeveloperSettingsObserver); super.onDetachedFromWindow(); } void disable(int state2) { final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0; if (disabled == mQsDisabled) return; mQsDisabled = disabled; updateEverything(); } void updateEverything() { post(() -> { updateVisibilities(); updateClickabilities(); setClickable(false); }); } private void updateClickabilities() { mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE); } private void updateVisibilities() { mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE); } }