1 /* 2 * Copyright (C) 2020 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.settings.development.storage; 18 19 import android.app.ActionBar; 20 import android.app.ListActivity; 21 import android.app.blob.BlobInfo; 22 import android.app.blob.BlobStoreManager; 23 import android.app.blob.LeaseInfo; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.pm.PackageManager; 27 import android.content.res.Resources; 28 import android.graphics.Typeface; 29 import android.graphics.drawable.Drawable; 30 import android.os.Bundle; 31 import android.text.TextUtils; 32 import android.util.Log; 33 import android.view.LayoutInflater; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.ViewGroup.LayoutParams; 37 import android.widget.ArrayAdapter; 38 import android.widget.Button; 39 import android.widget.LinearLayout; 40 import android.widget.TextView; 41 42 import androidx.appcompat.app.AlertDialog; 43 44 import com.android.internal.util.CollectionUtils; 45 import com.android.settings.R; 46 47 import java.io.IOException; 48 import java.util.List; 49 50 public class LeaseInfoListView extends ListActivity { 51 private static final String TAG = "LeaseInfoListView"; 52 53 private Context mContext; 54 private BlobStoreManager mBlobStoreManager; 55 private BlobInfo mBlobInfo; 56 private LeaseListAdapter mAdapter; 57 private LayoutInflater mInflater; 58 59 @Override onCreate(Bundle savedInstanceState)60 protected void onCreate(Bundle savedInstanceState) { 61 super.onCreate(savedInstanceState); 62 mContext = this; 63 mBlobStoreManager = (BlobStoreManager) getSystemService(BlobStoreManager.class); 64 mInflater = (LayoutInflater) getSystemService(LayoutInflater.class); 65 66 mBlobInfo = getIntent().getParcelableExtra(SharedDataUtils.BLOB_KEY); 67 68 mAdapter = new LeaseListAdapter(this); 69 if (mAdapter.isEmpty()) { 70 // this should never happen since we're checking the size in BlobInfoListView 71 Log.e(TAG, "Error fetching leases for shared data: " + mBlobInfo.toString()); 72 finish(); 73 } 74 75 setListAdapter(mAdapter); 76 getListView().addHeaderView(getHeaderView()); 77 getListView().addFooterView(getFooterView()); 78 getListView().setClickable(false); 79 80 final ActionBar actionBar = getActionBar(); 81 if (actionBar != null) { 82 actionBar.setDisplayHomeAsUpEnabled(true); 83 } 84 } 85 86 @Override onNavigateUp()87 public boolean onNavigateUp() { 88 finish(); 89 return true; 90 } 91 getHeaderView()92 private LinearLayout getHeaderView() { 93 final LinearLayout headerView = (LinearLayout) mInflater.inflate( 94 R.layout.blob_list_item_view , null); 95 headerView.setEnabled(false); // disable clicking 96 final TextView blobLabel = headerView.findViewById(R.id.blob_label); 97 final TextView blobId = headerView.findViewById(R.id.blob_id); 98 final TextView blobExpiry = headerView.findViewById(R.id.blob_expiry); 99 final TextView blobSize = headerView.findViewById(R.id.blob_size); 100 101 blobLabel.setText(mBlobInfo.getLabel()); 102 blobLabel.setTypeface(Typeface.DEFAULT_BOLD); 103 blobId.setText(getString(com.android.settingslib.R.string.blob_id_text, mBlobInfo.getId())); 104 blobExpiry.setVisibility(View.GONE); 105 blobSize.setText(SharedDataUtils.formatSize(mBlobInfo.getSizeBytes())); 106 return headerView; 107 } 108 getFooterView()109 private Button getFooterView() { 110 final Button deleteButton = new Button(this); 111 deleteButton.setLayoutParams( 112 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 113 deleteButton.setText(com.android.settingslib.R.string.delete_blob_text); 114 deleteButton.setOnClickListener(getButtonOnClickListener()); 115 return deleteButton; 116 } 117 getButtonOnClickListener()118 private View.OnClickListener getButtonOnClickListener() { 119 return v -> { 120 final AlertDialog dialog = new AlertDialog.Builder(mContext) 121 .setMessage(com.android.settingslib.R.string.delete_blob_confirmation_text) 122 .setPositiveButton(android.R.string.ok, getDialogOnClickListener()) 123 .setNegativeButton(android.R.string.cancel, null) 124 .create(); 125 dialog.show(); 126 }; 127 } 128 getDialogOnClickListener()129 private DialogInterface.OnClickListener getDialogOnClickListener() { 130 return (dialog, which) -> { 131 try { 132 mBlobStoreManager.deleteBlob(mBlobInfo); 133 setResult(SharedDataUtils.LEASE_VIEW_RESULT_CODE_SUCCESS); 134 } catch (IOException e) { 135 Log.e(TAG, "Unable to delete blob: " + e.getMessage()); 136 setResult(SharedDataUtils.LEASE_VIEW_RESULT_CODE_FAILURE); 137 } 138 finish(); 139 }; 140 } 141 142 private class LeaseListAdapter extends ArrayAdapter<LeaseInfo> { 143 private Context mContext; 144 145 LeaseListAdapter(Context context) { 146 super(context, 0); 147 148 mContext = context; 149 final List<LeaseInfo> leases = mBlobInfo.getLeases(); 150 if (CollectionUtils.isEmpty(leases)) { 151 return; 152 } 153 addAll(leases); 154 } 155 156 @Override 157 public View getView(int position, View convertView, ViewGroup parent) { 158 final LeaseInfoViewHolder holder = LeaseInfoViewHolder.createOrRecycle( 159 mInflater, convertView); 160 convertView = holder.rootView; 161 convertView.setEnabled(false); // disable clicking 162 163 final LeaseInfo lease = getItem(position); 164 Drawable appIcon; 165 try { 166 appIcon = mContext.getPackageManager().getApplicationIcon(lease.getPackageName()); 167 } catch (PackageManager.NameNotFoundException e) { 168 // set to system default app icon 169 appIcon = mContext.getDrawable(android.R.drawable.sym_def_app_icon); 170 } 171 holder.appIcon.setImageDrawable(appIcon); 172 holder.leasePackageName.setText(lease.getPackageName()); 173 holder.leaseDescription.setText(getDescriptionString(lease)); 174 holder.leaseExpiry.setText(formatExpiryTime(lease.getExpiryTimeMillis())); 175 return convertView; 176 } 177 178 private String getDescriptionString(LeaseInfo lease) { 179 String description = null; 180 try { 181 description = getString(lease.getDescriptionResId()); 182 } catch (Resources.NotFoundException ignored) { 183 if (lease.getDescription() != null) { 184 description = lease.getDescription().toString(); 185 } 186 } finally { 187 if (TextUtils.isEmpty(description)) { 188 description = getString( 189 com.android.settingslib.R.string.accessor_no_description_text); 190 } 191 } 192 return description; 193 } 194 195 private String formatExpiryTime(long expiryTimeMillis) { 196 if (expiryTimeMillis == 0) { 197 return getString(R.string.accessor_never_expires_text); 198 } 199 return getString(com.android.settingslib.R.string.accessor_expires_text, 200 SharedDataUtils.formatTime(expiryTimeMillis)); 201 } 202 } 203 } 204