| /* |
| * 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.Bundle; |
| import android.os.Handler; |
| import android.os.UserHandle; |
| import android.provider.Settings; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.view.accessibility.AccessibilityNodeInfo; |
| 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.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 mActionsContainer; |
| |
| protected TouchAnimator mFooterAnimator; |
| |
| private boolean mQsDisabled; |
| private boolean mExpanded; |
| private float mExpansionAmount; |
| |
| private boolean mShouldShowBuildText; |
| |
| 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); |
| mActionsContainer = requireViewById(R.id.qs_footer_actions); |
| mBuildText = findViewById(R.id.build); |
| |
| 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); |
| } |
| } |
| |
| void updateExpansion() { |
| setExpansion(mExpansionAmount); |
| } |
| |
| @Override |
| protected void onConfigurationChanged(Configuration newConfig) { |
| super.onConfigurationChanged(newConfig); |
| updateResources(); |
| } |
| |
| private void updateResources() { |
| updateFooterAnimator(); |
| MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); |
| lp.bottomMargin = getResources().getDimensionPixelSize(R.dimen.qs_footers_margin_bottom); |
| setLayoutParams(lp); |
| } |
| |
| private void updateFooterAnimator() { |
| mFooterAnimator = createFooterAnimator(); |
| } |
| |
| @Nullable |
| private TouchAnimator createFooterAnimator() { |
| TouchAnimator.Builder builder = new TouchAnimator.Builder() |
| .addFloat(mActionsContainer, "alpha", 0, 1) |
| .addFloat(mPageIndicator, "alpha", 0, 1) |
| .addFloat(mBuildText, "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(); |
| } |
| |
| @Override |
| public boolean performAccessibilityAction(int action, Bundle arguments) { |
| if (action == AccessibilityNodeInfo.ACTION_EXPAND) { |
| if (mExpandClickListener != null) { |
| mExpandClickListener.onClick(null); |
| return true; |
| } |
| } |
| return super.performAccessibilityAction(action, arguments); |
| } |
| |
| @Override |
| public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { |
| super.onInitializeAccessibilityNodeInfo(info); |
| info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND); |
| } |
| |
| 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); |
| } |
| } |