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.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 /** If bugreport TTL points go below this number, show a notice message. */ 42 private static final int MIN_TTL_POINTS_TO_SHOW_NOTICE = 10; 43 44 /** Provides a handler for click events*/ 45 interface ItemClickedListener { 46 /** 47 * Handles click events differently depending on provided buttonType and 48 * uses additional information provided in metaBugReport. 49 * 50 * @param buttonType One of {@link #BUTTON_TYPE_UPLOAD}, {@link #BUTTON_TYPE_MOVE} or 51 * {@link #BUTTON_TYPE_ADD_AUDIO}. 52 * @param metaBugReport Selected bugreport. 53 * @param holder ViewHolder of the clicked item. 54 */ onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder)55 void onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder); 56 } 57 58 /** 59 * Reference to each bug report info views. 60 */ 61 static class BugInfoViewHolder extends RecyclerView.ViewHolder { 62 /** Title view */ 63 TextView mTitleView; 64 65 /** Status View */ 66 TextView mStatusView; 67 68 /** Message View */ 69 TextView mMessageView; 70 71 /** Expiration Notice View */ 72 TextView mExpirationNoticeView; 73 74 /** Move Button */ 75 Button mMoveButton; 76 77 /** Upload Button */ 78 Button mUploadButton; 79 80 /** Add Audio Button */ 81 Button mAddAudioButton; 82 BugInfoViewHolder(View v)83 BugInfoViewHolder(View v) { 84 super(v); 85 mTitleView = itemView.findViewById(R.id.bug_info_row_title); 86 mStatusView = itemView.findViewById(R.id.bug_info_row_status); 87 mMessageView = itemView.findViewById(R.id.bug_info_row_status_message); 88 mExpirationNoticeView = itemView.findViewById(R.id.bug_info_row_expiration_notice); 89 mMoveButton = itemView.findViewById(R.id.bug_info_move_button); 90 mUploadButton = itemView.findViewById(R.id.bug_info_upload_button); 91 mAddAudioButton = itemView.findViewById(R.id.bug_info_add_audio_button); 92 } 93 } 94 95 private List<MetaBugReport> mDataset; 96 private final ItemClickedListener mItemClickedListener; 97 private final Config mConfig; 98 BugInfoAdapter(ItemClickedListener itemClickedListener, Config config)99 BugInfoAdapter(ItemClickedListener itemClickedListener, Config config) { 100 mItemClickedListener = itemClickedListener; 101 mDataset = new ArrayList<>(); 102 mConfig = config; 103 // Allow RecyclerView to efficiently update UI; getItemId() is implemented below. 104 setHasStableIds(true); 105 } 106 107 @Override onCreateViewHolder(ViewGroup parent, int viewType)108 public BugInfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 109 // create a new view 110 View v = LayoutInflater.from(parent.getContext()) 111 .inflate(R.layout.bug_info_view, parent, false); 112 return new BugInfoViewHolder(v); 113 } 114 115 @Override onBindViewHolder(BugInfoViewHolder holder, int position)116 public void onBindViewHolder(BugInfoViewHolder holder, int position) { 117 MetaBugReport bugreport = mDataset.get(position); 118 holder.mTitleView.setText(bugreport.getTitle()); 119 holder.mStatusView.setText(Status.toString(bugreport.getStatus())); 120 holder.mMessageView.setText(bugreport.getStatusMessage()); 121 if (bugreport.getStatusMessage().isEmpty()) { 122 holder.mMessageView.setVisibility(View.GONE); 123 } else { 124 holder.mMessageView.setVisibility(View.VISIBLE); 125 } 126 if (bugreport.getTtlPoints() <= MIN_TTL_POINTS_TO_SHOW_NOTICE 127 && BugStorageUtils.canBugReportBeExpired(bugreport.getStatus())) { 128 holder.mExpirationNoticeView.setVisibility(View.VISIBLE); 129 } else { 130 holder.mExpirationNoticeView.setVisibility(View.GONE); 131 } 132 boolean enableUserActionButtons = 133 bugreport.getStatus() == Status.STATUS_PENDING_USER_ACTION.getValue() 134 || bugreport.getStatus() == Status.STATUS_MOVE_FAILED.getValue() 135 || bugreport.getStatus() == Status.STATUS_UPLOAD_FAILED.getValue(); 136 if (enableUserActionButtons) { 137 holder.mMoveButton.setEnabled(true); 138 holder.mMoveButton.setVisibility(View.VISIBLE); 139 holder.mMoveButton.setOnClickListener( 140 view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_MOVE, bugreport, 141 holder)); 142 } else { 143 holder.mMoveButton.setEnabled(false); 144 holder.mMoveButton.setVisibility(View.GONE); 145 } 146 // Enable the upload button only for userdebug/eng builds. 147 if (enableUserActionButtons && Build.IS_DEBUGGABLE) { 148 holder.mUploadButton.setText(R.string.bugreport_upload_gcs_button_text); 149 holder.mUploadButton.setEnabled(true); 150 holder.mUploadButton.setVisibility(View.VISIBLE); 151 holder.mUploadButton.setOnClickListener( 152 view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_UPLOAD, bugreport, 153 holder)); 154 } else { 155 holder.mUploadButton.setVisibility(View.GONE); 156 holder.mUploadButton.setEnabled(false); 157 } 158 if (bugreport.getStatus() == Status.STATUS_AUDIO_PENDING.getValue()) { 159 if (mConfig.getAutoUpload()) { 160 holder.mAddAudioButton.setText(R.string.bugreport_add_audio_upload_button_text); 161 } else { 162 holder.mAddAudioButton.setText(R.string.bugreport_add_audio_button_text); 163 } 164 holder.mAddAudioButton.setEnabled(true); 165 holder.mAddAudioButton.setVisibility(View.VISIBLE); 166 holder.mAddAudioButton.setOnClickListener(view -> 167 mItemClickedListener.onItemClicked(BUTTON_TYPE_ADD_AUDIO, bugreport, holder)); 168 } else { 169 holder.mAddAudioButton.setEnabled(false); 170 holder.mAddAudioButton.setVisibility(View.GONE); 171 } 172 } 173 174 /** Sets dataSet; it copies the list, because it modifies it in this adapter. */ setDataset(List<MetaBugReport> bugReports)175 void setDataset(List<MetaBugReport> bugReports) { 176 mDataset = new ArrayList<>(bugReports); 177 notifyDataSetChanged(); 178 } 179 180 /** Update a bug report in the data set. */ updateBugReportInDataSet(MetaBugReport bugReport, int position)181 void updateBugReportInDataSet(MetaBugReport bugReport, int position) { 182 if (position != RecyclerView.NO_POSITION) { 183 mDataset.set(position, bugReport); 184 notifyItemChanged(position); 185 } 186 } 187 188 @Override getItemId(int position)189 public long getItemId(int position) { 190 return mDataset.get(position).getId(); 191 } 192 193 @Override getItemCount()194 public int getItemCount() { 195 return mDataset.size(); 196 } 197 } 198