1 /*
2  * Copyright (C) 2019 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 package com.google.android.car.bugreport;
17 
18 import android.os.Build;
19 import android.view.LayoutInflater;
20 import android.view.View;
21 import android.view.ViewGroup;
22 import android.widget.Button;
23 import android.widget.TextView;
24 
25 import androidx.recyclerview.widget.RecyclerView;
26 
27 import java.util.ArrayList;
28 import java.util.List;
29 
30 /**
31  * Shows bugreport title, status, status message and user action buttons. "Upload to Google" button
32  * is enabled when the status is {@link Status#STATUS_PENDING_USER_ACTION}, "Move to USB" button is
33  * enabled only when status is  {@link Status#STATUS_PENDING_USER_ACTION} and USB device is plugged
34  * in.
35  */
36 public class BugInfoAdapter extends RecyclerView.Adapter<BugInfoAdapter.BugInfoViewHolder> {
37     static final int BUTTON_TYPE_UPLOAD = 0;
38     static final int BUTTON_TYPE_MOVE = 1;
39     static final int BUTTON_TYPE_ADD_AUDIO = 2;
40 
41     /** Provides a handler for click events*/
42     interface ItemClickedListener {
43         /**
44          * Handles click events differently depending on provided buttonType and
45          * uses additional information provided in metaBugReport.
46          *
47          * @param buttonType One of {@link #BUTTON_TYPE_UPLOAD}, {@link #BUTTON_TYPE_MOVE} or
48          *                   {@link #BUTTON_TYPE_ADD_AUDIO}.
49          * @param metaBugReport Selected bugreport.
50          * @param holder ViewHolder of the clicked item.
51          */
onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder)52         void onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder);
53     }
54 
55     /**
56      * Reference to each bug report info views.
57      */
58     static class BugInfoViewHolder extends RecyclerView.ViewHolder {
59         /** Title view */
60         TextView mTitleView;
61 
62         /** Status View */
63         TextView mStatusView;
64 
65         /** Message View */
66         TextView mMessageView;
67 
68         /** Move Button */
69         Button mMoveButton;
70 
71         /** Upload Button */
72         Button mUploadButton;
73 
74         /** Add Audio Button */
75         Button mAddAudioButton;
76 
BugInfoViewHolder(View v)77         BugInfoViewHolder(View v) {
78             super(v);
79             mTitleView = itemView.findViewById(R.id.bug_info_row_title);
80             mStatusView = itemView.findViewById(R.id.bug_info_row_status);
81             mMessageView = itemView.findViewById(R.id.bug_info_row_message);
82             mMoveButton = itemView.findViewById(R.id.bug_info_move_button);
83             mUploadButton = itemView.findViewById(R.id.bug_info_upload_button);
84             mAddAudioButton = itemView.findViewById(R.id.bug_info_add_audio_button);
85         }
86     }
87 
88     private List<MetaBugReport> mDataset;
89     private final ItemClickedListener mItemClickedListener;
90     private final Config mConfig;
91 
BugInfoAdapter(ItemClickedListener itemClickedListener, Config config)92     BugInfoAdapter(ItemClickedListener itemClickedListener, Config config) {
93         mItemClickedListener = itemClickedListener;
94         mDataset = new ArrayList<>();
95         mConfig = config;
96         // Allow RecyclerView to efficiently update UI; getItemId() is implemented below.
97         setHasStableIds(true);
98     }
99 
100     @Override
onCreateViewHolder(ViewGroup parent, int viewType)101     public BugInfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
102         // create a new view
103         View v = LayoutInflater.from(parent.getContext())
104                 .inflate(R.layout.bug_info_view, parent, false);
105         return new BugInfoViewHolder(v);
106     }
107 
108     @Override
onBindViewHolder(BugInfoViewHolder holder, int position)109     public void onBindViewHolder(BugInfoViewHolder holder, int position) {
110         MetaBugReport bugreport = mDataset.get(position);
111         holder.mTitleView.setText(bugreport.getTitle());
112         holder.mStatusView.setText(Status.toString(bugreport.getStatus()));
113         holder.mMessageView.setText(bugreport.getStatusMessage());
114         if (bugreport.getStatusMessage().isEmpty()) {
115             holder.mMessageView.setVisibility(View.GONE);
116         } else {
117             holder.mMessageView.setVisibility(View.VISIBLE);
118         }
119         boolean enableUserActionButtons =
120                 bugreport.getStatus() == Status.STATUS_PENDING_USER_ACTION.getValue()
121                         || bugreport.getStatus() == Status.STATUS_MOVE_FAILED.getValue()
122                         || bugreport.getStatus() == Status.STATUS_UPLOAD_FAILED.getValue();
123         if (enableUserActionButtons) {
124             holder.mMoveButton.setEnabled(true);
125             holder.mMoveButton.setVisibility(View.VISIBLE);
126             holder.mMoveButton.setOnClickListener(
127                     view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_MOVE, bugreport,
128                             holder));
129         } else {
130             holder.mMoveButton.setEnabled(false);
131             holder.mMoveButton.setVisibility(View.GONE);
132         }
133         // Enable the upload button only for userdebug/eng builds.
134         if (enableUserActionButtons && Build.IS_DEBUGGABLE) {
135             holder.mUploadButton.setText(R.string.bugreport_upload_gcs_button_text);
136             holder.mUploadButton.setEnabled(true);
137             holder.mUploadButton.setVisibility(View.VISIBLE);
138             holder.mUploadButton.setOnClickListener(
139                     view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_UPLOAD, bugreport,
140                             holder));
141         } else {
142             holder.mUploadButton.setVisibility(View.GONE);
143             holder.mUploadButton.setEnabled(false);
144         }
145         if (bugreport.getStatus() == Status.STATUS_AUDIO_PENDING.getValue()) {
146             if (mConfig.getAutoUpload()) {
147                 holder.mAddAudioButton.setText(R.string.bugreport_add_audio_upload_button_text);
148             } else {
149                 holder.mAddAudioButton.setText(R.string.bugreport_add_audio_button_text);
150             }
151             holder.mAddAudioButton.setEnabled(true);
152             holder.mAddAudioButton.setVisibility(View.VISIBLE);
153             holder.mAddAudioButton.setOnClickListener(view ->
154                     mItemClickedListener.onItemClicked(BUTTON_TYPE_ADD_AUDIO, bugreport, holder));
155         } else {
156             holder.mAddAudioButton.setEnabled(false);
157             holder.mAddAudioButton.setVisibility(View.GONE);
158         }
159     }
160 
161     /** Sets dataSet; it copies the list, because it modifies it in this adapter. */
setDataset(List<MetaBugReport> bugReports)162     void setDataset(List<MetaBugReport> bugReports) {
163         mDataset = new ArrayList<>(bugReports);
164         notifyDataSetChanged();
165     }
166 
167     /** Update a bug report in the data set. */
updateBugReportInDataSet(MetaBugReport bugReport, int position)168     void updateBugReportInDataSet(MetaBugReport bugReport, int position) {
169         if (position != RecyclerView.NO_POSITION) {
170             mDataset.set(position, bugReport);
171             notifyItemChanged(position);
172         }
173     }
174 
175     @Override
getItemId(int position)176     public long getItemId(int position) {
177         return mDataset.get(position).getId();
178     }
179 
180     @Override
getItemCount()181     public int getItemCount() {
182         return mDataset.size();
183     }
184 }
185