• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.DeviceAsWebcam.view;
18 
19 import android.animation.ObjectAnimator;
20 import android.content.Context;
21 import android.util.AttributeSet;
22 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.view.animation.AccelerateDecelerateInterpolator;
25 import android.widget.FrameLayout;
26 import android.widget.TextView;
27 
28 import androidx.annotation.Nullable;
29 import androidx.constraintlayout.widget.ConstraintLayout;
30 import androidx.recyclerview.widget.LinearLayoutManager;
31 import androidx.recyclerview.widget.RecyclerView;
32 
33 import com.android.DeviceAsWebcam.CameraId;
34 import com.android.DeviceAsWebcam.R;
35 
36 import java.util.List;
37 import java.util.function.Consumer;
38 
39 /**
40  * A class to provide a switch-camera selector view for end users to select a preferred camera.
41  */
42 public class SwitchCameraSelectorView extends FrameLayout {
43     private List<SelectorListItemData> mSelectorListItemDataList;
44     private View mRootView;
45     private View mRecyclerViewContainerView;
46     private RecyclerView mRecyclerView;
47     private CameraDataAdapter mCameraDataAdapter;
48     private RecyclerView.LayoutManager mLayoutManager;
49     private Consumer<Integer> mVisibilityChangedListener = null;
50 
SwitchCameraSelectorView(Context context, AttributeSet attrs)51     public SwitchCameraSelectorView(Context context, AttributeSet attrs) {
52         super(context, attrs);
53     }
54 
55     /**
56      * Initializes the switch camera selector view.
57      */
init(LayoutInflater layoutInflater, List<SelectorListItemData> itemDataList)58     public void init(LayoutInflater layoutInflater, List<SelectorListItemData> itemDataList) {
59         removeAllViews();
60         addView(layoutInflater.inflate(R.layout.switch_camera_selector, null));
61         mSelectorListItemDataList = itemDataList;
62 
63         mRootView = findViewById(R.id.switch_camera_selector_root);
64         mRecyclerViewContainerView = findViewById(R.id.camera_id_list_container);
65         mRecyclerView = findViewById(R.id.camera_id_list_view);
66         findViewById(R.id.list_view_top_item).setEnabled(false);
67         findViewById(R.id.list_view_bottom_item).setEnabled(false);
68 
69         mCameraDataAdapter = new CameraDataAdapter(mSelectorListItemDataList, getResources());
70         mLayoutManager = new LinearLayoutManager(getContext());
71         mRecyclerView.setLayoutManager(mLayoutManager);
72         mRecyclerView.setAdapter(mCameraDataAdapter);
73 
74         mRootView.setOnClickListener(v -> hide());
75 
76         // Hides the camera selector in the beginning
77         hide();
78     }
79 
80     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)81     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
82         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
83 
84         // Dynamically calculates the suitable height for the dialog view because the dialog view
85         // is rotated from a portrait orientation layout to landscape.
86         if (mRecyclerViewContainerView != null) {
87             int listItemHeight = getResources().getDimensionPixelSize(
88                     R.dimen.list_item_height);
89             int topBottomHeight = getResources().getDimensionPixelSize(
90                     R.dimen.list_item_top_bottom_height);
91             int dialogHeight =
92                     listItemHeight * mSelectorListItemDataList.size() + topBottomHeight * 2;
93             int margin = getResources().getDimensionPixelSize(
94                     R.dimen.camera_selector_top_bottom_margin);
95             int expectedMargin = (getHeight() - dialogHeight) / 2;
96             int minMargin = (getHeight() - getWidth()) / 2 + margin;
97             int finalMargin = Math.max(expectedMargin, minMargin);
98             ConstraintLayout.LayoutParams lp =
99                     (ConstraintLayout.LayoutParams) mRecyclerViewContainerView.getLayoutParams();
100             lp.topMargin = finalMargin;
101             lp.bottomMargin = finalMargin;
102             mRecyclerViewContainerView.setLayoutParams(lp);
103         }
104     }
105 
106     /**
107      * Rotates the switch camera selector dialog.
108      */
setRotation(int rotation)109     public void setRotation(int rotation) {
110         ObjectAnimator anim = ObjectAnimator.ofFloat(mRecyclerViewContainerView,
111                         /*propertyName=*/"rotation", rotation)
112                 .setDuration(300);
113         anim.setInterpolator(new AccelerateDecelerateInterpolator());
114         anim.start();
115     }
116 
117     /**
118      * Sets a listener to receive the camera selection change events.
119      */
setOnCameraSelectedListener(Consumer<CameraId> listener)120     public void setOnCameraSelectedListener(Consumer<CameraId> listener) {
121         mCameraDataAdapter.setOnCameraSelectedListener(listener);
122     }
123 
124     /**
125      * Sets a listener to receive the visibility change events.
126      */
setOnVisibilityChangedListener(@ullable Consumer<Integer> listener)127     public void setOnVisibilityChangedListener(@Nullable Consumer<Integer> listener) {
128         mVisibilityChangedListener = listener;
129     }
130 
131     /**
132      * Shows the switch camera selector view.
133      */
show()134     public void show() {
135         mRootView.setAlpha(0f);
136         mRootView.setVisibility(VISIBLE);
137         if (mVisibilityChangedListener != null) {
138             mVisibilityChangedListener.accept(VISIBLE);
139         }
140 
141         mRootView.animate()
142                 .alpha(1f)
143                 .setDuration(300)
144                 .setListener(null);
145     }
146 
147     /**
148      * Hides the switch camera selector view.
149      */
hide()150     public void hide() {
151         mRootView.setVisibility(GONE);
152         if (mVisibilityChangedListener != null) {
153             mVisibilityChangedListener.accept(GONE);
154         }
155     }
156 
157     /**
158      * Updates the selected item.
159      */
updateSelectedItem(CameraId cameraId)160     public void updateSelectedItem(CameraId cameraId) {
161         for (SelectorListItemData itemData : mSelectorListItemDataList) {
162             if (itemData.isHeader) {
163                 continue;
164             }
165             boolean oldCheckedState = itemData.isChecked;
166             itemData.isChecked = itemData.cameraInfo.getCameraId().equals(cameraId);
167             if (oldCheckedState != itemData.isChecked) {
168                 mCameraDataAdapter.notifyItemChanged(
169                         mSelectorListItemDataList.indexOf(itemData));
170             }
171             if (itemData.isChecked) {
172                 mRecyclerView.scrollToPosition(mSelectorListItemDataList.indexOf(itemData));
173             }
174         }
175     }
176 }
177