Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f73b0cb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add stop casting button for output switch"

parents cb9f4448 201b48b8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11749,4 +11749,6 @@
    <!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
    <string name="rtt_settings_always_visible"></string>
    <!-- Button label to stop casting on media device. [CHAR LIMIT=40 -->
    <string name="media_output_panel_stop_casting_button">Stop casting</string>
</resources>
+82 −3
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.settings.panel;

import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;

import static com.android.settings.media.MediaOutputSlice.MEDIA_PACKAGE_NAME;
import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI;

@@ -35,9 +38,15 @@ import android.text.TextUtils;
import android.util.Log;

import androidx.core.graphics.drawable.IconCompat;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settingslib.media.InfoMediaDevice;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;

import java.util.ArrayList;
import java.util.List;
@@ -49,13 +58,20 @@ import java.util.List;
 * Displays Media output item
 * </p>
 */
public class MediaOutputPanel implements PanelContent {
public class MediaOutputPanel implements PanelContent, LocalMediaManager.DeviceCallback,
        LifecycleObserver {

    private static final String TAG = "MediaOutputPanel";

    private final Context mContext;
    private final String mPackageName;

    private PanelCustomizedButtonCallback mCallback;
    private boolean mIsCustomizedButtonUsed = true;

    @VisibleForTesting
    LocalMediaManager mLocalMediaManager;

    private MediaSessionManager mMediaSessionManager;
    private MediaController mMediaController;

@@ -65,8 +81,9 @@ public class MediaOutputPanel implements PanelContent {

    private MediaOutputPanel(Context context, String packageName) {
        mContext = context.getApplicationContext();
        mPackageName = packageName;
        if (mPackageName != null) {
        mPackageName = TextUtils.isEmpty(packageName) ? "" : packageName;

        if (!TextUtils.isEmpty(mPackageName)) {
            mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
            for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
                if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
@@ -75,6 +92,7 @@ public class MediaOutputPanel implements PanelContent {
                }
            }
        }

        if (mMediaController == null) {
            Log.e(TAG, "Unable to find " + mPackageName + " media controller");
        }
@@ -156,8 +174,69 @@ public class MediaOutputPanel implements PanelContent {
        return null;
    }

    @Override
    public boolean isCustomizedButtonUsed() {
        return mIsCustomizedButtonUsed;
    }

    @Override
    public CharSequence getCustomButtonTitle() {
        return mContext.getText(R.string.media_output_panel_stop_casting_button);
    }

    @Override
    public void onClickCustomizedButton() {
    }

    @Override
    public void registerCallback(PanelCustomizedButtonCallback callback) {
        mCallback = callback;
    }

    @Override
    public int getMetricsCategory() {
        return SettingsEnums.PANEL_MEDIA_OUTPUT;
    }

    @Override
    public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
        dispatchCustomButtonStateChanged();
    }

    @Override
    public void onDeviceListUpdate(List<MediaDevice> devices) {
        dispatchCustomButtonStateChanged();
    }

    @Override
    public void onDeviceAttributesChanged() {
        dispatchCustomButtonStateChanged();
    }

    private void dispatchCustomButtonStateChanged() {
        hideCustomButtonIfNecessary();
        if (mCallback != null) {
            mCallback.onCustomizedButtonStateChanged();
        }
    }

    private void hideCustomButtonIfNecessary() {
        final MediaDevice device = mLocalMediaManager.getCurrentConnectedDevice();
        mIsCustomizedButtonUsed = device instanceof InfoMediaDevice;
    }

    @OnLifecycleEvent(ON_START)
    public void onStart() {
        if (mLocalMediaManager == null) {
            mLocalMediaManager = new LocalMediaManager(mContext, mPackageName, null);
        }
        mLocalMediaManager.registerCallback(this);
        mLocalMediaManager.startScan();
    }

    @OnLifecycleEvent(ON_STOP)
    public void onStop() {
        mLocalMediaManager.unregisterCallback(this);
        mLocalMediaManager.stopScan();
    }
}
+27 −0
Original line number Diff line number Diff line
@@ -74,4 +74,31 @@ public interface PanelContent extends Instrumentable {
    default Intent getHeaderIconIntent() {
        return null;
    }

    /**
     * @return {@code true} to enable custom button to replace see more button,
     * {@code false} otherwise.
     */
    default boolean isCustomizedButtonUsed() {
        return false;
    }

    /**
     * @return a string for the title of the custom button.
     */
    default CharSequence getCustomButtonTitle() {
        return null;
    }

    /**
     * Implement the click event for custom button.
     */
    default void onClickCustomizedButton() {}

    /**
     * Register to start receiving callbacks for custom button events.
     *
     * @param callback the callback to add.
     */
    default void registerCallback(PanelCustomizedButtonCallback callback) {}
}
+29 −0
Original line number Diff line number Diff line
/*
 * 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.settings.panel;

/**
 * PanelCustomizedButtonCallback provides a callback interface for {@link PanelFragment} to receive
 * events from {@link PanelContent}.
 */
public interface PanelCustomizedButtonCallback {

    /**
     * It will be called when customized button state is changed. For example, custom button
     * would be hidden for specific behavior.
     */
    void onCustomizedButtonStateChanged();
}
+34 −5
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.IconCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -53,6 +54,7 @@ import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.panel.PanelLoggingContract.PanelClosedKeys;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;

import com.google.android.setupdesign.DividerItemDecoration;

@@ -183,6 +185,11 @@ public class PanelFragment extends Fragment {
            activity.finish();
        }

        mPanel.registerCallback(new LocalPanelCallback());
        if (mPanel instanceof LifecycleObserver) {
            getLifecycle().addObserver((LifecycleObserver) mPanel);
        }

        mMetricsProvider = FeatureFactory.getFactory(activity).getMetricsFeatureProvider();

        mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));
@@ -208,8 +215,15 @@ public class PanelFragment extends Fragment {
        mSeeMoreButton.setOnClickListener(getSeeMoreListener());
        mDoneButton.setOnClickListener(getCloseListener());

        // If getSeeMoreIntent() is null, hide the mSeeMoreButton.
        if (mPanel.getSeeMoreIntent() == null) {
        if (mPanel.isCustomizedButtonUsed()) {
            final CharSequence customTitle = mPanel.getCustomButtonTitle();
            if (TextUtils.isEmpty(customTitle)) {
                mSeeMoreButton.setVisibility(View.GONE);
            } else {
                mSeeMoreButton.setText(customTitle);
            }
        } else if (mPanel.getSeeMoreIntent() == null) {
            // If getSeeMoreIntent() is null hide the mSeeMoreButton.
            mSeeMoreButton.setVisibility(View.GONE);
        }

@@ -371,9 +385,13 @@ public class PanelFragment extends Fragment {
    View.OnClickListener getSeeMoreListener() {
        return (v) -> {
            mPanelClosedKey = PanelClosedKeys.KEY_SEE_MORE;
            if (mPanel.isCustomizedButtonUsed()) {
                mPanel.onClickCustomizedButton();
            } else {
                final FragmentActivity activity = getActivity();
                activity.startActivityForResult(mPanel.getSeeMoreIntent(), 0);
                activity.finish();
            }
        };
    }

@@ -392,4 +410,15 @@ public class PanelFragment extends Fragment {
            activity.startActivity(mPanel.getHeaderIconIntent());
        };
    }

    class LocalPanelCallback implements PanelCustomizedButtonCallback {

        @Override
        public void onCustomizedButtonStateChanged() {
            ThreadUtils.postOnMainThread(() -> {
                mSeeMoreButton.setVisibility(
                        mPanel.isCustomizedButtonUsed() ? View.VISIBLE : View.GONE);
            });
        }
    }
}
Loading