├── ic_launcher-web.png ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── values │ ├── strings.xml │ └── styles.xml ├── layout │ ├── activity_item_detail.xml │ ├── activity_item_list.xml │ ├── fragment_item_detail.xml │ └── activity_item_twopane.xml ├── values-v11 │ └── styles.xml ├── values-large │ └── refs.xml ├── values-sw600dp │ └── refs.xml └── values-v14 │ └── styles.xml ├── README.md ├── .gitignore ├── project.properties ├── LICENSE ├── tools ├── pushAndRun-debug ├── pushAndRun-release ├── build-debug ├── build-release └── update.sh ├── ant.properties ├── proguard-project.txt ├── AndroidManifest.xml └── src └── jackpal └── droidexaminer ├── ItemDetailFragment.java ├── ItemDetailActivity.java ├── ItemListActivity.java ├── ItemListFragment.java └── content └── Content.java /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackpal/droid-examiner/HEAD/ic_launcher-web.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackpal/droid-examiner/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackpal/droid-examiner/HEAD/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackpal/droid-examiner/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackpal/droid-examiner/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Droid Examiner 5 | Item Detail 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | droid-examiner 2 | ============== 3 | 4 | An Android utility for examining Linux system internals of an Android device. 5 | 6 | This is the source code for the Droid Examiner android app. 7 | 8 | https://play.google.com/store/apps/details?id=jackpal.droidexaminer&hl=en 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build artifacts 2 | bin/ 3 | gen/ 4 | libs/ 5 | 6 | # Signing key, kept secret 7 | tools/droid-examiner.keystore 8 | 9 | # Eclipse project files 10 | .classpath 11 | .project 12 | .settings/ 13 | 14 | # Generated by tools/update.sh 15 | build.xml 16 | local.properties 17 | 18 | lint.xml 19 | -------------------------------------------------------------------------------- /res/layout/activity_item_detail.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /res/values-large/refs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | @layout/activity_item_twopane 11 | 12 | -------------------------------------------------------------------------------- /res/values-sw600dp/refs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | @layout/activity_item_twopane 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /res/layout/activity_item_list.xml: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-16 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Jack Palevich 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /res/layout/fragment_item_detail.xml: -------------------------------------------------------------------------------- 1 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /tools/pushAndRun-debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # command line build script for installing and running terminal emulator. 3 | set -e 4 | 5 | if [ -z "${ANDROID_SDK_ROOT+xxx}" ]; then 6 | echo "Please define ANDROID_SDK_ROOT to point to the Android SDK" 7 | exit 1 8 | fi 9 | 10 | if [ ! -d "$ANDROID_SDK_ROOT" ]; then 11 | echo "The directory $ANDROID_SDK_ROOT = ${ANDROID_NDK_ROOT} does not exist." 12 | exit 1 13 | fi 14 | 15 | ADB="$ANDROID_SDK_ROOT/platform-tools/adb" 16 | 17 | $ADB uninstall jackpal.droidexaminer 18 | $ADB install -r bin/DroidExaminer-debug.apk && $ADB shell am start -n jackpal.droidexaminer/jackpal.droidexaminer.ItemListActivity 19 | -------------------------------------------------------------------------------- /tools/pushAndRun-release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # command line build script for installing and running terminal emulator. 3 | set -e 4 | 5 | if [ -z "${ANDROID_SDK_ROOT+xxx}" ]; then 6 | echo "Please define ANDROID_SDK_ROOT to point to the Android SDK" 7 | exit 1 8 | fi 9 | 10 | if [ ! -d "$ANDROID_SDK_ROOT" ]; then 11 | echo "The directory $ANDROID_SDK_ROOT = ${ANDROID_NDK_ROOT} does not exist." 12 | exit 1 13 | fi 14 | 15 | ADB="$ANDROID_SDK_ROOT/platform-tools/adb" 16 | 17 | $ADB uninstall jackpal.droidexaminer 18 | $ADB install -r bin/DroidExaminer-release.apk && adb shell am start -n jackpal.droidexaminer/jackpal.droidexaminer.ItemListActivity 19 | -------------------------------------------------------------------------------- /tools/build-debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # command line build script for building the debug version 3 | set -e 4 | 5 | if [ -z "${ANDROID_SDK_ROOT+xxx}" ]; then 6 | echo "Please define ANDROID_SDK_ROOT to point to the Android SDK" 7 | exit 1 8 | fi 9 | 10 | if [ ! -d "$ANDROID_SDK_ROOT" ]; then 11 | echo "The directory $ANDROID_SDK_ROOT = ${ANDROID_NDK_ROOT} does not exist." 12 | exit 1 13 | fi 14 | 15 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 16 | ATE_ROOT="$( cd $DIR/.. && pwd )" 17 | 18 | cd "$ATE_ROOT" 19 | 20 | if [ ! -f "local.properties" ]; then 21 | echo "local.properties does not exist. Please run tools/update.sh" 22 | exit 1 23 | fi 24 | 25 | rm -rf `find . -name bin -o -name obj -prune` 26 | 27 | ant debug 28 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /ant.properties: -------------------------------------------------------------------------------- 1 | # This file is used to override default values used by the Ant build system. 2 | # 3 | # This file must be checked in Version Control Systems, as it is 4 | # integral to the build system of your project. 5 | 6 | # This file is only used by the Ant script. 7 | 8 | # You can use this to override default values such as 9 | # 'source.dir' for the location of your java source folder and 10 | # 'out.dir' for the location of your output folder. 11 | 12 | # You can also use it define how the release builds are signed by declaring 13 | # the following properties: 14 | # 'key.store' for the location of your keystore and 15 | # 'key.alias' for the name of the key to use. 16 | # The password will be asked during the build when you use the 'release' target. 17 | 18 | key.alias=release 19 | key.store=tools/droid-examiner.keystore 20 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /tools/build-release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # command line build script for building release version 3 | # This will only work on my (Jack Palevich) computer, because it 4 | # requires the private key store used o sign the release version 5 | # of Android Terminal Emulator. 6 | set -e 7 | 8 | if [ -z "${ANDROID_SDK_ROOT+xxx}" ]; then 9 | echo "Please define ANDROID_SDK_ROOT to point to the Android SDK" 10 | exit 1 11 | fi 12 | 13 | if [ ! -d "$ANDROID_SDK_ROOT" ]; then 14 | echo "The directory $ANDROID_SDK_ROOT = ${ANDROID_NDK_ROOT} does not exist." 15 | exit 1 16 | fi 17 | 18 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 19 | ATE_ROOT="$( cd $DIR/.. && pwd )" 20 | 21 | cd "$ATE_ROOT" 22 | 23 | if [ ! -f "local.properties" ]; then 24 | echo "local.properties does not exist. Please run tools/update.sh" 25 | exit 1 26 | fi 27 | 28 | rm -rf `find . -name bin -o -name obj -prune` 29 | 30 | ant release 31 | -------------------------------------------------------------------------------- /tools/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # You have to run this once in order for ant builds to work 3 | set -e 4 | 5 | if [ -z "${ANDROID_SDK_ROOT+xxx}" ]; then 6 | echo "Please define ANDROID_SDK_ROOT to point to the Android SDK" 7 | exit 1 8 | fi 9 | 10 | if [ ! -d "$ANDROID_SDK_ROOT" ]; then 11 | echo "The directory $ANDROID_SDK_ROOT = ${ANDROID_SDK_ROOT} does not exist." 12 | exit 1 13 | fi 14 | 15 | ANDROID="$ANDROID_SDK_ROOT/tools/android" 16 | 17 | command -v "$ANDROID" >/dev/null 2>&1 || { echo >&2 "The $ANDROID tool is not found. Aborting."; exit 1; } 18 | 19 | ANDROID_TARGET=android-16 20 | 21 | # Make sure ANDROID_TARGET is installed 22 | 23 | $ANDROID update sdk -a -u -t $ANDROID_TARGET 24 | 25 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 26 | APP_ROOT="$( cd $DIR/.. && pwd )" 27 | 28 | # Copy the Android Support jar file from the SDK to our libs directory. 29 | mkdir -p $APP_ROOT/libs 30 | 31 | cp $ANDROID_SDK_ROOT/extras/android/support/v4/android-support-v4.jar $APP_ROOT/libs 32 | 33 | echo "Updating android project files" 34 | 35 | $ANDROID update project -p "$APP_ROOT" --target $ANDROID_TARGET 36 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /res/layout/activity_item_twopane.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 30 | 31 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/jackpal/droidexaminer/ItemDetailFragment.java: -------------------------------------------------------------------------------- 1 | package jackpal.droidexaminer; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import jackpal.droidexaminer.R; 11 | import jackpal.droidexaminer.content.Content; 12 | 13 | /** 14 | * A fragment representing a single Item detail screen. 15 | * This fragment is either contained in a {@link ItemListActivity} 16 | * in two-pane mode (on tablets) or a {@link ItemDetailActivity} 17 | * on handsets. 18 | */ 19 | public class ItemDetailFragment extends Fragment { 20 | /** 21 | * The fragment argument representing the item ID that this fragment 22 | * represents. 23 | */ 24 | public static final String ARG_ITEM_ID = "item_id"; 25 | 26 | /** 27 | * The dummy content this fragment is presenting. 28 | */ 29 | private Content.Item mItem; 30 | 31 | /** 32 | * Mandatory empty constructor for the fragment manager to instantiate the 33 | * fragment (e.g. upon screen orientation changes). 34 | */ 35 | public ItemDetailFragment() { 36 | } 37 | 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | 42 | if (getArguments().containsKey(ARG_ITEM_ID)) { 43 | // Load the dummy content specified by the fragment 44 | // arguments. In a real-world scenario, use a Loader 45 | // to load content from a content provider. 46 | mItem = Content.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID)); 47 | } 48 | } 49 | 50 | @Override 51 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 52 | Bundle savedInstanceState) { 53 | View rootView = inflater.inflate(R.layout.fragment_item_detail, container, false); 54 | 55 | // Show the dummy content as text in a TextView. 56 | if (mItem != null) { 57 | ((TextView) rootView.findViewById(R.id.item_detail)).setText(mItem.getContents()); 58 | } 59 | 60 | return rootView; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/jackpal/droidexaminer/ItemDetailActivity.java: -------------------------------------------------------------------------------- 1 | package jackpal.droidexaminer; 2 | 3 | import jackpal.droidexaminer.R; 4 | import jackpal.droidexaminer.content.Content; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.support.v4.app.NavUtils; 9 | import android.view.MenuItem; 10 | 11 | /** 12 | * An activity representing a single Item detail screen. This 13 | * activity is only used on handset devices. On tablet-size devices, 14 | * item details are presented side-by-side with a list of items 15 | * in a {@link ItemListActivity}. 16 | *

17 | * This activity is mostly just a 'shell' activity containing nothing 18 | * more than a {@link ItemDetailFragment}. 19 | */ 20 | public class ItemDetailActivity extends FragmentActivity { 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | Content.init(getApplicationContext()); 26 | setContentView(R.layout.activity_item_detail); 27 | 28 | // Show the Up button in the action bar. 29 | getActionBar().setDisplayHomeAsUpEnabled(true); 30 | 31 | // savedInstanceState is non-null when there is fragment state 32 | // saved from previous configurations of this activity 33 | // (e.g. when rotating the screen from portrait to landscape). 34 | // In this case, the fragment will automatically be re-added 35 | // to its container so we don't need to manually add it. 36 | // For more information, see the Fragments API guide at: 37 | // 38 | // http://developer.android.com/guide/components/fragments.html 39 | // 40 | if (savedInstanceState == null) { 41 | // Create the detail fragment and add it to the activity 42 | // using a fragment transaction. 43 | Bundle arguments = new Bundle(); 44 | arguments.putString(ItemDetailFragment.ARG_ITEM_ID, 45 | getIntent().getStringExtra(ItemDetailFragment.ARG_ITEM_ID)); 46 | ItemDetailFragment fragment = new ItemDetailFragment(); 47 | fragment.setArguments(arguments); 48 | getSupportFragmentManager().beginTransaction() 49 | .add(R.id.item_detail_container, fragment) 50 | .commit(); 51 | } 52 | } 53 | 54 | @Override 55 | public boolean onOptionsItemSelected(MenuItem item) { 56 | switch (item.getItemId()) { 57 | case android.R.id.home: 58 | // This ID represents the Home or Up button. In the case of this 59 | // activity, the Up button is shown. Use NavUtils to allow users 60 | // to navigate up one level in the application structure. For 61 | // more details, see the Navigation pattern on Android Design: 62 | // 63 | // http://developer.android.com/design/patterns/navigation.html#up-vs-back 64 | // 65 | NavUtils.navigateUpTo(this, new Intent(this, ItemListActivity.class)); 66 | return true; 67 | } 68 | return super.onOptionsItemSelected(item); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/jackpal/droidexaminer/ItemListActivity.java: -------------------------------------------------------------------------------- 1 | package jackpal.droidexaminer; 2 | 3 | import jackpal.droidexaminer.R; 4 | import jackpal.droidexaminer.content.Content; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.FragmentActivity; 8 | 9 | 10 | /** 11 | * An activity representing a list of Items. This activity 12 | * has different presentations for handset and tablet-size devices. On 13 | * handsets, the activity presents a list of items, which when touched, 14 | * lead to a {@link ItemDetailActivity} representing 15 | * item details. On tablets, the activity presents the list of items and 16 | * item details side-by-side using two vertical panes. 17 | *

18 | * The activity makes heavy use of fragments. The list of items is a 19 | * {@link ItemListFragment} and the item details 20 | * (if present) is a {@link ItemDetailFragment}. 21 | *

22 | * This activity also implements the required 23 | * {@link ItemListFragment.Callbacks} interface 24 | * to listen for item selections. 25 | */ 26 | public class ItemListActivity extends FragmentActivity 27 | implements ItemListFragment.Callbacks { 28 | 29 | /** 30 | * Whether or not the activity is in two-pane mode, i.e. running on a tablet 31 | * device. 32 | */ 33 | private boolean mTwoPane; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | Content.init(getApplicationContext()); 39 | setContentView(R.layout.activity_item_list); 40 | 41 | if (findViewById(R.id.item_detail_container) != null) { 42 | // The detail container view will be present only in the 43 | // large-screen layouts (res/values-large and 44 | // res/values-sw600dp). If this view is present, then the 45 | // activity should be in two-pane mode. 46 | mTwoPane = true; 47 | 48 | // In two-pane mode, list items should be given the 49 | // 'activated' state when touched. 50 | ((ItemListFragment) getSupportFragmentManager() 51 | .findFragmentById(R.id.item_list)) 52 | .setActivateOnItemClick(true); 53 | } 54 | 55 | // TODO: If exposing deep links into your app, handle intents here. 56 | } 57 | 58 | /** 59 | * Callback method from {@link ItemListFragment.Callbacks} 60 | * indicating that the item with the given ID was selected. 61 | */ 62 | @Override 63 | public void onItemSelected(String id) { 64 | if (mTwoPane) { 65 | // In two-pane mode, show the detail view in this activity by 66 | // adding or replacing the detail fragment using a 67 | // fragment transaction. 68 | Bundle arguments = new Bundle(); 69 | arguments.putString(ItemDetailFragment.ARG_ITEM_ID, id); 70 | ItemDetailFragment fragment = new ItemDetailFragment(); 71 | fragment.setArguments(arguments); 72 | getSupportFragmentManager().beginTransaction() 73 | .replace(R.id.item_detail_container, fragment) 74 | .commit(); 75 | 76 | } else { 77 | // In single-pane mode, simply start the detail activity 78 | // for the selected item ID. 79 | Intent detailIntent = new Intent(this, ItemDetailActivity.class); 80 | detailIntent.putExtra(ItemDetailFragment.ARG_ITEM_ID, id); 81 | startActivity(detailIntent); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/jackpal/droidexaminer/ItemListFragment.java: -------------------------------------------------------------------------------- 1 | package jackpal.droidexaminer; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v4.app.ListFragment; 6 | import android.view.View; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.ListView; 9 | 10 | import jackpal.droidexaminer.content.Content; 11 | 12 | /** 13 | * A list fragment representing a list of Items. This fragment 14 | * also supports tablet devices by allowing list items to be given an 15 | * 'activated' state upon selection. This helps indicate which item is 16 | * currently being viewed in a {@link ItemDetailFragment}. 17 | *

18 | * Activities containing this fragment MUST implement the {@link Callbacks} 19 | * interface. 20 | */ 21 | public class ItemListFragment extends ListFragment { 22 | 23 | /** 24 | * The serialization (saved instance state) Bundle key representing the 25 | * activated item position. Only used on tablets. 26 | */ 27 | private static final String STATE_ACTIVATED_POSITION = "activated_position"; 28 | 29 | /** 30 | * The fragment's current callback object, which is notified of list item 31 | * clicks. 32 | */ 33 | private Callbacks mCallbacks = sDummyCallbacks; 34 | 35 | /** 36 | * The current activated item position. Only used on tablets. 37 | */ 38 | private int mActivatedPosition = ListView.INVALID_POSITION; 39 | 40 | /** 41 | * A callback interface that all activities containing this fragment must 42 | * implement. This mechanism allows activities to be notified of item 43 | * selections. 44 | */ 45 | public interface Callbacks { 46 | /** 47 | * Callback for when an item has been selected. 48 | */ 49 | public void onItemSelected(String id); 50 | } 51 | 52 | /** 53 | * A dummy implementation of the {@link Callbacks} interface that does 54 | * nothing. Used only when this fragment is not attached to an activity. 55 | */ 56 | private static Callbacks sDummyCallbacks = new Callbacks() { 57 | @Override 58 | public void onItemSelected(String id) { 59 | } 60 | }; 61 | 62 | /** 63 | * Mandatory empty constructor for the fragment manager to instantiate the 64 | * fragment (e.g. upon screen orientation changes). 65 | */ 66 | public ItemListFragment() { 67 | } 68 | 69 | @Override 70 | public void onCreate(Bundle savedInstanceState) { 71 | super.onCreate(savedInstanceState); 72 | 73 | // TODO: replace with a real list adapter. 74 | setListAdapter(new ArrayAdapter( 75 | getActivity(), 76 | android.R.layout.simple_list_item_activated_1, 77 | android.R.id.text1, 78 | Content.ITEMS)); 79 | } 80 | 81 | @Override 82 | public void onViewCreated(View view, Bundle savedInstanceState) { 83 | super.onViewCreated(view, savedInstanceState); 84 | 85 | // Restore the previously serialized activated item position. 86 | if (savedInstanceState != null 87 | && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { 88 | setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION)); 89 | } 90 | } 91 | 92 | @Override 93 | public void onAttach(Activity activity) { 94 | super.onAttach(activity); 95 | 96 | // Activities containing this fragment must implement its callbacks. 97 | if (!(activity instanceof Callbacks)) { 98 | throw new IllegalStateException("Activity must implement fragment's callbacks."); 99 | } 100 | 101 | mCallbacks = (Callbacks) activity; 102 | } 103 | 104 | @Override 105 | public void onDetach() { 106 | super.onDetach(); 107 | 108 | // Reset the active callbacks interface to the dummy implementation. 109 | mCallbacks = sDummyCallbacks; 110 | } 111 | 112 | @Override 113 | public void onListItemClick(ListView listView, View view, int position, long id) { 114 | super.onListItemClick(listView, view, position, id); 115 | 116 | // Notify the active callbacks interface (the activity, if the 117 | // fragment is attached to one) that an item has been selected. 118 | mCallbacks.onItemSelected(Content.ITEMS.get(position).id); 119 | } 120 | 121 | @Override 122 | public void onSaveInstanceState(Bundle outState) { 123 | super.onSaveInstanceState(outState); 124 | if (mActivatedPosition != ListView.INVALID_POSITION) { 125 | // Serialize and persist the activated item position. 126 | outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); 127 | } 128 | } 129 | 130 | /** 131 | * Turns on activate-on-click mode. When this mode is on, list items will be 132 | * given the 'activated' state when touched. 133 | */ 134 | public void setActivateOnItemClick(boolean activateOnItemClick) { 135 | // When setting CHOICE_MODE_SINGLE, ListView will automatically 136 | // give items the 'activated' state when touched. 137 | getListView().setChoiceMode(activateOnItemClick 138 | ? ListView.CHOICE_MODE_SINGLE 139 | : ListView.CHOICE_MODE_NONE); 140 | } 141 | 142 | private void setActivatedPosition(int position) { 143 | if (position == ListView.INVALID_POSITION) { 144 | getListView().setItemChecked(mActivatedPosition, false); 145 | } else { 146 | getListView().setItemChecked(position, true); 147 | } 148 | 149 | mActivatedPosition = position; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/jackpal/droidexaminer/content/Content.java: -------------------------------------------------------------------------------- 1 | package jackpal.droidexaminer.content; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.Formatter; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Locale; 14 | import java.util.Map; 15 | 16 | import android.app.ActivityManager; 17 | import android.content.Context; 18 | import android.content.Intent; 19 | import android.content.IntentFilter; 20 | import android.content.pm.ConfigurationInfo; 21 | import android.content.res.Configuration; 22 | import android.hardware.Camera; 23 | import android.hardware.Sensor; 24 | import android.hardware.SensorManager; 25 | import android.opengl.GLES10; 26 | import android.os.BatteryManager; 27 | import android.os.Build; 28 | import android.os.Environment; 29 | import android.os.StatFs; 30 | import android.text.format.DateFormat; 31 | import android.util.Log; 32 | import android.util.Pair; 33 | import android.view.Display; 34 | import android.view.InputDevice; 35 | import android.view.WindowManager; 36 | 37 | /** 38 | * Helper class for providing sample content for user interfaces created by 39 | * Android template wizards. 40 | *

41 | * TODO: Replace all uses of this class before publishing your app. 42 | */ 43 | public class Content { 44 | private static Context sContext; 45 | private static java.text.DateFormat sDateFormat; 46 | private static java.text.DateFormat sTimeFormat; 47 | 48 | /** 49 | * An array of sample (dummy) items. 50 | */ 51 | public static List ITEMS = new ArrayList(); 52 | 53 | /** 54 | * A map of sample (dummy) items, by ID. 55 | */ 56 | public static Map ITEM_MAP = new HashMap(); 57 | 58 | private static void addItem(Item item) { 59 | ITEMS.add(item); 60 | ITEM_MAP.put(item.id, item); 61 | } 62 | 63 | /** 64 | * A dummy item representing a piece of content. 65 | */ 66 | public static abstract class Item { 67 | public final String id; 68 | private final String mLabel; 69 | 70 | public Item(String id, String label) { 71 | this.id = id; 72 | this.mLabel = label;; 73 | } 74 | 75 | public String getLabel() { 76 | return mLabel; 77 | } 78 | 79 | public abstract String getContents(); 80 | 81 | @Override 82 | public String toString() { 83 | return mLabel; 84 | } 85 | } 86 | 87 | private static class PIS extends Pair { 88 | public PIS(int i, String s) { 89 | super(i, s); 90 | } 91 | }; 92 | 93 | private static String formatBitmask(int bits, List l, boolean allowOverlapping) { 94 | StringBuilder sb = new StringBuilder(); 95 | Formatter f = new Formatter(sb); 96 | String prefix = ""; 97 | for (PIS p: l) { 98 | int mask = p.first; 99 | if (mask != 0 && mask == (mask & bits)) { 100 | f.format("%s%s", prefix, p.second); 101 | if (! allowOverlapping) { 102 | bits &= ~mask; 103 | } 104 | prefix = "|"; 105 | } 106 | } 107 | if (bits != 0) { 108 | f.format("%s0x%x", prefix, bits); 109 | } 110 | return sb.toString(); 111 | } 112 | 113 | public static class BuildItem extends Item { 114 | 115 | public BuildItem(String id, String label) { 116 | super(id, label); 117 | } 118 | 119 | public String getContents() { 120 | StringBuilder sb = new StringBuilder(); 121 | Formatter f = new Formatter(sb, Locale.US); 122 | f.format("board: %s\n", Build.BOARD); 123 | f.format("bootloader: %s\n", Build.BOOTLOADER); 124 | f.format("brand: %s\n", Build.BRAND); 125 | f.format("cpu_abi: %s\n", Build.CPU_ABI); 126 | f.format("cpu_abi2: %s\n", Build.CPU_ABI2); 127 | f.format("device: %s\n", Build.DEVICE); 128 | f.format("display: %s\n", Build.DISPLAY); 129 | f.format("fingerprint: %s\n", Build.FINGERPRINT); 130 | f.format("hardware: %s\n", Build.HARDWARE); 131 | f.format("host: %s\n", Build.HOST); 132 | f.format("id: %s\n", Build.ID); 133 | f.format("manufacturer: %s\n", Build.MANUFACTURER); 134 | f.format("model: %s\n", Build.MODEL); 135 | f.format("product: %s\n", Build.PRODUCT); 136 | // f.format("radio: %s\n", Build.RADIO); 137 | f.format("serial: %s\n", Build.SERIAL); 138 | f.format("tags: %s\n", Build.TAGS); 139 | f.format("time: %s %s\n", sDateFormat.format(Build.TIME), sTimeFormat.format(Build.TIME)); 140 | f.format("type: %s\n", Build.TYPE); 141 | f.format("user: %s\n", Build.USER); 142 | 143 | String s = sb.toString(); 144 | Log.i("BuildItem", s); 145 | return s; 146 | } 147 | } 148 | 149 | 150 | public static class RuntimeItem extends Item { 151 | 152 | public RuntimeItem(String id, String label) { 153 | super(id, label); 154 | } 155 | 156 | public String getContents() { 157 | StringBuilder sb = new StringBuilder(); 158 | Formatter f = new Formatter(sb, Locale.US); 159 | Runtime r = Runtime.getRuntime(); 160 | f.format("availableProcessors: %d\n", r.availableProcessors()); 161 | f.format("freeMemory: %s\n", formatFileSize(r.freeMemory())); 162 | f.format("totalMemory: %s\n", formatFileSize(r.totalMemory())); 163 | f.format("maxMemory: %s\n", formatFileSize(r.maxMemory())); 164 | 165 | return sb.toString(); 166 | } 167 | } 168 | 169 | public static class ConfigurationInfoItem extends Item { 170 | private final ConfigurationInfo mConfigurationInfo; 171 | 172 | public ConfigurationInfoItem(String id, String label, ConfigurationInfo info) { 173 | super(id, label); 174 | mConfigurationInfo = info; 175 | } 176 | 177 | public String getContents() { 178 | StringBuilder sb = new StringBuilder(); 179 | Formatter f = new Formatter(sb, Locale.US); 180 | ConfigurationInfo c = mConfigurationInfo; 181 | f.format("ConfigurationInfo: %s\n", c); 182 | f.format("glEsVersion: %s\n", c.getGlEsVersion()); 183 | f.format("inputFeatures: %x\n", c.reqInputFeatures); 184 | f.format("keyboardType: %x\n", c.reqKeyboardType); 185 | f.format("navigation: %x\n", c.reqNavigation); 186 | f.format("touchScreen: %x\n", c.reqTouchScreen); 187 | return sb.toString(); 188 | } 189 | } 190 | 191 | public static class ConfigItem extends Item { 192 | private static final String TAG = "ConfigItem"; 193 | private final String mContents; 194 | 195 | public ConfigItem(String id, String label, Context context) { 196 | super(id, label); 197 | mContents = getConfig(context); 198 | Log.i(TAG, mContents); 199 | } 200 | 201 | private String getConfig(Context context) { 202 | StringBuilder sb = new StringBuilder(); 203 | Configuration config = context.getResources().getConfiguration(); 204 | Locale locale = config.locale; 205 | Formatter f = new Formatter(sb, locale); 206 | f.format("Config: %s\n", config); 207 | // API level 17 f.format("densityDpi = %d", config.densityDpi); 208 | f.format("fontScale: %g\n", config.fontScale); 209 | f.format("hardKeyboardHidden: %d\n", config.hardKeyboardHidden); 210 | f.format("keyboard: %d\n", config.keyboard); 211 | f.format("keyboardHidden: %d\n", config.keyboardHidden); 212 | f.format("locale: %s\n", config.locale); 213 | f.format("mcc: %d\n", config.mcc); 214 | f.format("mnc: %d\n", config.mnc); 215 | f.format("navigation: %d\n", config.navigation); 216 | f.format("navigationHidden: %d\n", config.navigationHidden); 217 | f.format("orientation: %d\n", config.orientation); 218 | f.format("screenHeightDp: %d\n", config.screenHeightDp); 219 | f.format("screenLayout: 0x%x\n", config.screenLayout); 220 | f.format("screenWidthDp: %d\n", config.screenWidthDp); 221 | f.format("smallestScreenWidthDp: %d\n", config.smallestScreenWidthDp); 222 | f.format("touchscreen: %d\n", config.touchscreen); 223 | f.format("uiMode: %s\n", formatBitmask(config.uiMode, Arrays.asList( 224 | new PIS(Configuration.UI_MODE_TYPE_UNDEFINED, "UI_MODE_TYPE_UNDEFINED"), 225 | new PIS(Configuration.UI_MODE_TYPE_NORMAL, "UI_MODE_TYPE_NORMAL"), 226 | new PIS(Configuration.UI_MODE_TYPE_DESK, "UI_MODE_TYPE_DESK"), 227 | new PIS(Configuration.UI_MODE_TYPE_CAR, "UI_MODE_TYPE_CAR"), 228 | new PIS(Configuration.UI_MODE_TYPE_TELEVISION, "UI_MODE_TYPE_TELEVISION"), 229 | new PIS(Configuration.UI_MODE_TYPE_APPLIANCE, "UI_MODE_TYPE_APPLIANCE"), 230 | new PIS(Configuration.UI_MODE_NIGHT_NO, "UI_MODE_NIGHT_NO"), 231 | new PIS(Configuration.UI_MODE_NIGHT_YES, "UI_MODE_NIGHT_YES") 232 | ), false)); 233 | return sb.toString(); 234 | } 235 | 236 | public String getContents() { 237 | return mContents; 238 | } 239 | } 240 | 241 | public static class OpenGLItem extends Item { 242 | 243 | public OpenGLItem(String id, String label) { 244 | super(id, label); 245 | } 246 | 247 | public String getContents() { 248 | StringBuilder sb = new StringBuilder(); 249 | Formatter f = new Formatter(sb, Locale.US); 250 | String vendor = GLES10.glGetString(GLES10.GL_VENDOR); 251 | if (vendor == null) { 252 | f.format("!!! Please tap on another tab and then tap back on this tab. !!!\n\n"); 253 | } 254 | f.format("vendor: %s\n", vendor); 255 | f.format("version: %s\n", GLES10.glGetString(GLES10.GL_VERSION)); 256 | String extensions = GLES10.glGetString(GLES10.GL_EXTENSIONS); 257 | if (extensions == null) { 258 | extensions = ""; 259 | } 260 | f.format("extensions: %s\n", extensions.replaceAll(" ", "\n")); 261 | return sb.toString(); 262 | } 263 | } 264 | 265 | public static class FileInfo extends Item { 266 | private String mPath; 267 | 268 | public FileInfo(String id, String label, String path) { 269 | super(id, label); 270 | mPath = path; 271 | } 272 | 273 | public String getContents() { 274 | return mPath + ":\n" + readFile(mPath); 275 | } 276 | } 277 | 278 | public static class InputDeviceInfo extends Item { 279 | public InputDeviceInfo(String id, String label) { 280 | super(id, label); 281 | } 282 | 283 | public String getContents() { 284 | StringBuilder sb = new StringBuilder(); 285 | Formatter f = new Formatter(sb, Locale.US); 286 | int[] ids = InputDevice.getDeviceIds(); 287 | f.format("Device count: %d\n", ids.length); 288 | for (int i = 0; i < ids.length; i++) { 289 | int id = ids[i]; 290 | InputDevice device = InputDevice.getDevice(id); 291 | f.format("#%d: id = 0x%x\n%s\n", i, id, device); 292 | } 293 | return sb.toString(); 294 | } 295 | } 296 | 297 | 298 | public static class SensorsItem extends Item { 299 | final private SensorManager mManager; 300 | public SensorsItem(String id, String label, SensorManager manager) { 301 | super(id, label); 302 | mManager = manager; 303 | } 304 | 305 | public String getContents() { 306 | StringBuilder sb = new StringBuilder(); 307 | Formatter f = new Formatter(sb, Locale.US); 308 | List sensors = mManager.getSensorList(Sensor.TYPE_ALL); 309 | f.format("Sensor count: %d\n", sensors.size()); 310 | for (int i = 0; i < sensors.size(); i++) { 311 | Sensor s = sensors.get(i); 312 | f.format("#%d: %s\n", i, s); 313 | } 314 | return sb.toString(); 315 | } 316 | } 317 | 318 | public static class BatteryItem extends Item { 319 | public BatteryItem(String id, String label) { 320 | super(id, label); 321 | } 322 | 323 | public String getContents() { 324 | StringBuilder sb = new StringBuilder(); 325 | Formatter f = new Formatter(sb, Locale.US); 326 | IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 327 | Intent batteryStatus = sContext.registerReceiver(null, ifilter); 328 | f.format("present: %b\n", batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false)); 329 | f.format("technology: %s\n", batteryStatus.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY)); 330 | f.format("status: %d\n", batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1)); 331 | f.format("plugged: %d\n", batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)); 332 | f.format("health: %d\n", batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH, -1)); 333 | f.format("level: %d of %d\n", batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1), 334 | batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1)); 335 | f.format("temperature: %d\n", batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1)); 336 | f.format("voltage: %d\n", batteryStatus.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1)); 337 | return sb.toString(); 338 | } 339 | } 340 | 341 | public static class CamerasItem extends Item { 342 | public CamerasItem(String id, String label) { 343 | super(id, label); 344 | } 345 | 346 | public String getContents() { 347 | StringBuilder sb = new StringBuilder(); 348 | Formatter f = new Formatter(sb, Locale.US); 349 | int cameraCount = Camera.getNumberOfCameras(); 350 | f.format("Camera count: %d\n", cameraCount); 351 | for (int i = 0; i < cameraCount; i++) { 352 | Camera.CameraInfo info = new Camera.CameraInfo(); 353 | Camera.getCameraInfo(i, info); 354 | f.format("#%d: %s\n", i, info); 355 | // f.format("canDisableShutterSound: %b\n", info.canDisableShutterSound); 356 | f.format("facing: %d\n", info.facing); 357 | f.format("orientation: %d\n", info.orientation); 358 | } 359 | return sb.toString(); 360 | } 361 | } 362 | 363 | public static class DisplayMetricsItem extends Item { 364 | public DisplayMetricsItem(String id, String label) { 365 | super(id, label); 366 | } 367 | 368 | public String getContents() { 369 | StringBuilder sb = new StringBuilder(); 370 | Formatter f = new Formatter(sb, Locale.US); 371 | WindowManager windowManager = (WindowManager)sContext.getSystemService(Context.WINDOW_SERVICE); 372 | Display display = windowManager.getDefaultDisplay(); 373 | f.format("%s\n", display); 374 | return sb.toString(); 375 | } 376 | } 377 | 378 | public static class StorageItem extends Item { 379 | public StorageItem(String id, String label) { 380 | super(id, label); 381 | } 382 | 383 | public String getContents() { 384 | StringBuilder sb = new StringBuilder(); 385 | Formatter f = new Formatter(sb, Locale.US); 386 | formatStorage(f, Environment.getRootDirectory()); 387 | formatStorage(f, Environment.getDataDirectory()); 388 | f.format("External storage is emulated: %s\n", Environment.isExternalStorageEmulated()); 389 | f.format("External storage is removable: %s\n", Environment.isExternalStorageRemovable()); 390 | f.format("External storage state: %s\n", Environment.getExternalStorageState()); 391 | formatStorage(f, Environment.getExternalStorageDirectory()); 392 | return sb.toString(); 393 | } 394 | 395 | private void formatStorage(Formatter f, File file) { 396 | String path = file.getPath(); 397 | StatFs stat = new StatFs(path); 398 | long bytesAvailable = (long)stat.getBlockSize() * (long)stat.getBlockCount(); 399 | f.format("path: %s size: %s\n", path, formatFileSize(bytesAvailable)); 400 | } 401 | } 402 | static String readFile(String path) { 403 | BufferedReader reader; 404 | try { 405 | reader = new BufferedReader( new FileReader (path)); 406 | } catch (FileNotFoundException e) { 407 | // TODO Auto-generated catch block 408 | return "Could not open " + path; 409 | } 410 | StringBuilder sb = new StringBuilder(); 411 | String line; 412 | String ls = System.getProperty("line.separator"); 413 | 414 | try { 415 | while( ( line = reader.readLine() ) != null ) { 416 | sb.append( line ); 417 | sb.append( ls ); 418 | } 419 | } catch (IOException e) { 420 | sb.append("--- io exception: " + e); 421 | } 422 | 423 | return sb.toString(); 424 | } 425 | 426 | 427 | public static void init(Context context) { 428 | ITEMS.clear(); 429 | ITEM_MAP.clear(); 430 | 431 | sContext = context; 432 | sDateFormat = DateFormat.getDateFormat(context); 433 | sTimeFormat = DateFormat.getTimeFormat(context); 434 | int id = 1; 435 | addItem(new BuildItem(Integer.toString(id++), "Build")); 436 | addItem(new BatteryItem(Integer.toString(id++), "Battery")); 437 | addItem(new CamerasItem(Integer.toString(id++), "Cameras")); 438 | addItem(new ConfigItem(Integer.toString(id++), "Configuration", context)); 439 | final ActivityManager activityManager = 440 | (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 441 | final ConfigurationInfo configurationInfo = 442 | activityManager.getDeviceConfigurationInfo(); 443 | addItem(new ConfigurationInfoItem(Integer.toString(id++), "ConfigurationInfo", configurationInfo)); 444 | addItem(new FileInfo(Integer.toString(id++), "CpuInfo", "/proc/cpuinfo")); 445 | addItem(new FileInfo(Integer.toString(id++), "Crypto", "/proc/crypto")); 446 | addItem(new FileInfo(Integer.toString(id++), "Devices", "/proc/devices")); 447 | addItem(new FileInfo(Integer.toString(id++), "DiskStats", "/proc/diskstats")); 448 | addItem(new DisplayMetricsItem(Integer.toString(id++), "Display")); 449 | addItem(new FileInfo(Integer.toString(id++), "Filesystems", "/proc/filesystems")); 450 | addItem(new InputDeviceInfo(Integer.toString(id++), "Input Devices")); 451 | addItem(new FileInfo(Integer.toString(id++), "Kernel Version", "/proc/version")); 452 | addItem(new FileInfo(Integer.toString(id++), "LoadAvg", "/proc/loadavg")); 453 | addItem(new FileInfo(Integer.toString(id++), "Memory", "/proc/meminfo")); 454 | addItem(new FileInfo(Integer.toString(id++), "Modules", "/proc/modules")); 455 | addItem(new OpenGLItem(Integer.toString(id++), "OpenGL")); 456 | addItem(new RuntimeItem(Integer.toString(id++), "Runtime")); 457 | addItem(new SensorsItem(Integer.toString(id++), "Sensors", (SensorManager) context.getSystemService(Context.SENSOR_SERVICE))); 458 | addItem(new StorageItem(Integer.toString(id++), "Storage")); 459 | addItem(new FileInfo(Integer.toString(id++), "Uptime", "/proc/uptime")); 460 | } 461 | 462 | private static String formatFileSize(long n) { 463 | return android.text.format.Formatter.formatFileSize(sContext, n); 464 | } 465 | } 466 | --------------------------------------------------------------------------------