1 /* 2 * Copyright (C) 2017 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.documentsui.inspector; 17 18 import android.content.Context; 19 import android.content.res.Resources; 20 import android.os.AsyncTask; 21 import android.os.Bundle; 22 import android.provider.DocumentsContract; 23 import android.util.AttributeSet; 24 import android.widget.TextView; 25 26 import androidx.annotation.StringRes; 27 28 import com.android.documentsui.R; 29 import com.android.documentsui.base.DocumentInfo; 30 import com.android.documentsui.base.Lookup; 31 import com.android.documentsui.base.StubLookup; 32 import com.android.documentsui.inspector.InspectorController.DebugDisplay; 33 34 import java.text.NumberFormat; 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 import java.util.Collections; 38 import java.util.List; 39 import java.util.concurrent.Executor; 40 41 /** 42 * Organizes and Displays the debug information about a file. This view 43 * should only be made visible when build is debuggable and system policies 44 * allow debug "stuff". 45 */ 46 public class DebugView extends TableView implements DebugDisplay { 47 48 private final Context mContext; 49 private final Resources mRes; 50 private Lookup<String, Executor> mExecutors = new StubLookup<>(); 51 DebugView(Context context)52 public DebugView(Context context) { 53 this(context, null); 54 } 55 DebugView(Context context, AttributeSet attrs)56 public DebugView(Context context, AttributeSet attrs) { 57 this(context, attrs, 0); 58 } 59 DebugView(Context context, AttributeSet attrs, int defStyleAttr)60 public DebugView(Context context, AttributeSet attrs, int defStyleAttr) { 61 super(context, attrs, defStyleAttr); 62 mContext = context; 63 mRes = context.getResources(); 64 } 65 init(Lookup<String, Executor> executors)66 void init(Lookup<String, Executor> executors) { 67 assert executors != null; 68 mExecutors = executors; 69 } 70 71 @Override accept(DocumentInfo info)72 public void accept(DocumentInfo info) { 73 setTitle(R.string.inspector_debug_section, true); 74 75 put(R.string.debug_user_id, info.userId.toString()); 76 put(R.string.debug_content_uri, info.derivedUri.toString()); 77 put(R.string.debug_document_id, info.documentId); 78 put(R.string.debug_raw_mimetype, info.mimeType); 79 put(R.string.debug_stream_types, "-"); 80 put(R.string.debug_raw_size, NumberFormat.getInstance().format(info.size)); 81 put(R.string.debug_is_archive, info.isArchive()); 82 put(R.string.debug_is_blocked_from_tree, info.isBlockedFromTree()); 83 put(R.string.debug_is_container, info.isContainer()); 84 put(R.string.debug_is_partial, info.isPartial()); 85 put(R.string.debug_is_virtual, info.isVirtual()); 86 put(R.string.debug_supports_create, info.isCreateSupported()); 87 put(R.string.debug_supports_delete, info.isDeleteSupported()); 88 put(R.string.debug_supports_metadata, info.isMetadataSupported()); 89 put(R.string.debug_supports_move, info.isMoveSupported()); 90 put(R.string.debug_supports_remove, info.isRemoveSupported()); 91 put(R.string.debug_supports_rename, info.isRenameSupported()); 92 put(R.string.debug_supports_settings, info.isSettingsSupported()); 93 put(R.string.debug_supports_thumbnail, info.isThumbnailSupported()); 94 put(R.string.debug_supports_weblink, info.isWeblinkSupported()); 95 put(R.string.debug_supports_write, info.isWriteSupported()); 96 97 // Load Document stream types of the file. For virtual files, this should be 98 // something other than the primary type of the file. 99 Executor executor = mExecutors.lookup(info.derivedUri.getAuthority()); 100 if (executor != null) { 101 new AsyncTask<Void, Void, String[]>() { 102 @Override 103 protected String[] doInBackground(Void... params) { 104 return mContext.getContentResolver().getStreamTypes(info.derivedUri, "*/*"); 105 } 106 107 @Override 108 protected void onPostExecute(String[] streamTypes) { 109 put(R.string.debug_stream_types, 110 streamTypes != null ? Arrays.toString(streamTypes) : "[]"); 111 } 112 }.executeOnExecutor(executor, (Void[]) null); 113 } 114 } 115 116 @Override accept(Bundle metadata)117 public void accept(Bundle metadata) { 118 if (metadata == null) { 119 return; 120 } 121 122 String[] types = metadata.getStringArray(DocumentsContract.METADATA_TYPES); 123 if (types == null) { 124 return; 125 } 126 127 for (String type : types) { 128 dumpMetadata(type, metadata.getBundle(type)); 129 } 130 } 131 dumpMetadata(String type, Bundle bundle)132 private void dumpMetadata(String type, Bundle bundle) { 133 String title = mContext.getResources().getString( 134 R.string.inspector_debug_metadata_section); 135 putTitle(String.format(title, type), true); 136 List<String> keys = new ArrayList<>(bundle.keySet()); 137 Collections.sort(keys); 138 for (String key : keys) { 139 put(key, String.valueOf(bundle.get(key))); 140 } 141 } 142 put(@tringRes int key, boolean value)143 private void put(@StringRes int key, boolean value) { 144 KeyValueRow row = put(mRes.getString(key), String.valueOf(value)); 145 TextView valueView = ((TextView) row.findViewById(R.id.table_row_value)); 146 valueView.setTextColor(value ? 0xFF006400 : 0xFF9A2020); 147 } 148 } 149