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