Android Tutorial - Core Class : Resources
Resources Management
package apt.tutorial; import android.app.TabActivity; import android.os.Bundle; import android.os.SystemClock; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.LayoutInflater; import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.RadioGroup; import android.widget.TabHost; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; public class LunchList extends TabActivity { List<Restaurant> model=new ArrayList<Restaurant>(); RestaurantAdapter adapter=null; EditText name=null; EditText address=null; EditText notes=null; RadioGroup types=null; Restaurant current=null; AtomicBoolean isActive=new AtomicBoolean(true); int progress=0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.main); name=(EditText)findViewById(R.id.name); address=(EditText)findViewById(R.id.addr); notes=(EditText)findViewById(R.id.notes); types=(RadioGroup)findViewById(R.id.types); Button save=(Button)findViewById(R.id.save); save.setOnClickListener(onSave); ListView list=(ListView)findViewById(R.id.restaurants); adapter=new RestaurantAdapter(); list.setAdapter(adapter); TabHost.TabSpec spec=getTabHost().newTabSpec("tag1"); spec.setContent(R.id.restaurants); spec.setIndicator("List", getResources() .getDrawable(R.drawable.list)); getTabHost().addTab(spec); spec=getTabHost().newTabSpec("tag2"); spec.setContent(R.id.details); spec.setIndicator("Details", getResources() .getDrawable(R.drawable.restaurant)); getTabHost().addTab(spec); getTabHost().setCurrentTab(0); list.setOnItemClickListener(onListClick); } @Override public void onPause() { super.onPause(); isActive.set(false); } @Override public void onResume() { super.onResume(); isActive.set(true); if (progress>0) { startWork(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { new MenuInflater(this).inflate(R.menu.option, menu); return(super.onCreateOptionsMenu(menu)); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId()==R.id.toast) { String message="No restaurant selected"; if (current!=null) { message=current.getNotes(); } Toast.makeText(this, message, Toast.LENGTH_LONG).show(); return(true); } else if (item.getItemId()==R.id.run) { startWork(); return(true); } return(super.onOptionsItemSelected(item)); } private void startWork() { setProgressBarVisibility(true); new Thread(longTask).start(); } private void doSomeLongWork(final int incr) { runOnUiThread(new Runnable() { public void run() { progress+=incr; setProgress(progress); } }); SystemClock.sleep(250); // should be something more useful! } private View.OnClickListener onSave=new View.OnClickListener() { public void onClick(View v) { current=new Restaurant(); current.setName(name.getText().toString()); current.setAddress(address.getText().toString()); current.setNotes(notes.getText().toString()); switch (types.getCheckedRadioButtonId()) { case R.id.sit_down: current.setType("sit_down"); break; case R.id.take_out: current.setType("take_out"); break; case R.id.delivery: current.setType("delivery"); break; } adapter.add(current); } }; private AdapterView.OnItemClickListener onListClick=new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { current=model.get(position); name.setText(current.getName()); address.setText(current.getAddress()); notes.setText(current.getNotes()); if (current.getType().equals("sit_down")) { types.check(R.id.sit_down); } else if (current.getType().equals("take_out")) { types.check(R.id.take_out); } else { types.check(R.id.delivery); } getTabHost().setCurrentTab(1); } }; private Runnable longTask=new Runnable() { public void run() { for (int i=progress; i<10000 && isActive.get(); i+=200) { doSomeLongWork(200); } if (isActive.get()) { runOnUiThread(new Runnable() { public void run() { setProgressBarVisibility(false); progress=0; } }); } } }; class RestaurantAdapter extends ArrayAdapter<Restaurant> { RestaurantAdapter() { super(LunchList.this, R.layout.row, model); } public View getView(int position, View convertView, ViewGroup parent) { View row=convertView; RestaurantHolder holder=null; if (row==null) { LayoutInflater inflater=getLayoutInflater(); row=inflater.inflate(R.layout.row, parent, false); holder=new RestaurantHolder(row); row.setTag(holder); } else { holder=(RestaurantHolder)row.getTag(); } holder.populateFrom(model.get(position)); return(row); } } static class RestaurantHolder { private TextView name=null; private TextView address=null; private ImageView icon=null; RestaurantHolder(View row) { name=(TextView)row.findViewById(R.id.title); address=(TextView)row.findViewById(R.id.address); icon=(ImageView)row.findViewById(R.id.icon); } void populateFrom(Restaurant r) { name.setText(r.getName()); address.setText(r.getAddress()); if (r.getType().equals("sit_down")) { icon.setImageResource(R.drawable.ball_red); } else if (r.getType().equals("take_out")) { icon.setImageResource(R.drawable.ball_yellow); } else { icon.setImageResource(R.drawable.ball_green); } } } } package apt.tutorial; public class Restaurant { private String name=""; private String address=""; private String type=""; private String notes=""; public String getName() { return(name); } public void setName(String name) { this.name=name; } public String getAddress() { return(address); } public void setAddress(String address) { this.address=address; } public String getType() { return(type); } public void setType(String type) { this.type=type; } public String getNotes() { return(notes); } public void setNotes(String notes) { this.notes=notes; } public String toString() { return(getName()); } } //layout/main.xml <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/restaurants" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> <TableLayout android:id="@+id/details" android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="1" android:paddingTop="4dip" > <TableRow> <TextView android:text="Name:" /> <EditText android:id="@+id/name" /> </TableRow> <TableRow> <TextView android:text="Address:" /> <EditText android:id="@+id/addr" /> </TableRow> <TableRow> <TextView android:text="Type:" /> <RadioGroup android:id="@+id/types"> <RadioButton android:id="@+id/take_out" android:text="Take-Out" /> <RadioButton android:id="@+id/sit_down" android:text="Sit-Down" /> <RadioButton android:id="@+id/delivery" android:text="Delivery" /> </RadioGroup> </TableRow> <TableRow> <TextView android:text="Notes:" /> <EditText android:id="@+id/notes" android:singleLine="false" android:gravity="top" android:lines="2" android:scrollHorizontally="false" android:maxLines="2" android:maxWidth="200sp" /> </TableRow> <Button android:id="@+id/save" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Save" /> </TableLayout> </FrameLayout> </LinearLayout> </TabHost> //layout/row.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="4dip" > <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_alignParentTop="true" android:layout_alignParentBottom="true" android:layout_marginRight="4dip" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center_vertical" android:textStyle="bold" android:singleLine="true" android:ellipsize="end" /> <TextView android:id="@+id/address" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center_vertical" android:singleLine="true" android:ellipsize="end" /> </LinearLayout> </LinearLayout> //layout-land.xml <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/restaurants" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TableLayout android:id="@+id/details" android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="1,3" android:paddingTop="4dip" > <TableRow> <TextView android:text="Name:" android:paddingRight="2dip" /> <EditText android:id="@+id/name" android:maxWidth="140sp" /> <TextView android:text="Address:" android:paddingLeft="2dip" android:paddingRight="2dip" /> <EditText android:id="@+id/addr" android:maxWidth="140sp" /> </TableRow> <TableRow> <TextView android:text="Type:" /> <RadioGroup android:id="@+id/types"> <RadioButton android:id="@+id/take_out" android:text="Take-Out" /> <RadioButton android:id="@+id/sit_down" android:text="Sit-Down" /> <RadioButton android:id="@+id/delivery" android:text="Delivery" /> </RadioGroup> <TextView android:text="Notes:" android:paddingLeft="2dip" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <EditText android:id="@+id/notes" android:singleLine="false" android:gravity="top" android:lines="3" android:scrollHorizontally="false" android:maxLines="3" android:maxWidth="140sp" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/save" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Save" /> </LinearLayout> </TableRow> </TableLayout> </FrameLayout> </LinearLayout> </TabHost> //option.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/toast" android:title="Raise Toast" android:icon="@drawable/toast" /> <item android:id="@+id/run" android:title="Run Long Task" android:icon="@drawable/run" /> </menu> //strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">LunchList</string> </resources>
Load resource from raw folder
package com.commonsware.android.files; import android.app.Activity; import android.os.Bundle; import android.app.ListActivity; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.io.InputStream; import java.util.ArrayList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public class StaticFileDemo extends ListActivity { TextView selection; ArrayList<String> items=new ArrayList<String>(); @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); selection=(TextView)findViewById(R.id.selection); try { InputStream in=getResources().openRawResource(R.raw.words); DocumentBuilder builder=DocumentBuilderFactory .newInstance() .newDocumentBuilder(); Document doc=builder.parse(in, null); NodeList words=doc.getElementsByTagName("word"); for (int i=0;i<words.getLength();i++) { items.add(((Element)words.item(i)).getAttribute("value")); } in.close(); } catch (Throwable t) { Toast .makeText(this, "Exception: "+t.toString(), 2000) .show(); } setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items)); } public void onListItemClick(ListView parent, View v, int position, long id) { selection.setText(items.get(position).toString()); } } //res\raw\words.xml <words> <word value="lorem" /> <word value="ipsum" /> <word value="dolor" /> <word value="sit" /> <word value="amet" /> <word value="consectetuer" /> <word value="adipiscing" /> <word value="elit" /> <word value="morbi" /> <word value="vel" /> <word value="ligula" /> <word value="vitae" /> <word value="arcu" /> <word value="aliquet" /> <word value="mollis" /> <word value="etiam" /> <word value="vel" /> <word value="erat" /> <word value="placerat" /> <word value="ante" /> <word value="porttitor" /> <word value="sodales" /> <word value="pellentesque" /> <word value="augue" /> <word value="purus" /> </words> //res\layout\main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/selection" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:drawSelectorOnTop="false" /> </LinearLayout>
Multiple Resource
package com.example.android.multires; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; public final class MultiRes extends Activity { private int mCurrentPhotoIndex = 0; private int[] mPhotoIds = new int[] { R.drawable.sample_0, R.drawable.sample_1, R.drawable.sample_2, R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6, R.drawable.sample_7 }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); showPhoto(mCurrentPhotoIndex); // Handle clicks on the 'Next' button. Button nextButton = (Button) findViewById(R.id.next_button); nextButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mCurrentPhotoIndex = (mCurrentPhotoIndex + 1) % mPhotoIds.length; showPhoto(mCurrentPhotoIndex); } }); } @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt("photo_index", mCurrentPhotoIndex); super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { mCurrentPhotoIndex = savedInstanceState.getInt("photo_index"); showPhoto(mCurrentPhotoIndex); super.onRestoreInstanceState(savedInstanceState); } private void showPhoto(int photoIndex) { ImageView imageView = (ImageView) findViewById(R.id.image_view); imageView.setImageResource(mPhotoIds[photoIndex]); TextView statusText = (TextView) findViewById(R.id.status_text); statusText.setText(String.format("%d/%d", photoIndex + 1, mPhotoIds.length)); } } // //res\layout\main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/background"> <LinearLayout android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/image_container" android:background="@drawable/image_container"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/image_view" android:scaleType="fitCenter"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:id="@+id/status_text" android:textColor="@android:color/primary_text_dark" android:textSize="16sp" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1" android:layout_margin="5dip" android:shadowColor="@android:color/background_dark"/> </FrameLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:gravity="center"> <Button android:text="@string/next_button" android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/android" android:textSize="24sp"/> </LinearLayout> </LinearLayout> // //res\layout-land\main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:background="@drawable/background"> <LinearLayout android:layout_weight="1" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:background="@drawable/image_container" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/image_container"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/image_view" android:scaleType="fitCenter"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:id="@+id/status_text" android:textColor="@android:color/primary_text_dark" android:textSize="16sp" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1" android:layout_margin="5dip" android:shadowColor="@android:color/background_dark"/> </FrameLayout> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="vertical" android:layout_marginLeft="10dip" android:gravity="top"> <Button android:text="@string/next_button" android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/android" android:textSize="24sp"/> </LinearLayout> </LinearLayout> // //res\values\strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">MultiRes</string> <string name="next_button">Next</string> </resources>
Demonstration of loading resources.
package app.test; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.os.Bundle; import android.widget.TextView; public class ResourcesSample extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // See res/any/layout/resources.xml for this view layout definition. setContentView(R.layout.main); TextView tv; CharSequence cs; String str; // Using the Context.getString() convenience method // Using the getString() convenience method, retrieve a string // resource that happens to have style information. Note the use of // CharSequence instead of String so we don't lose the style info. cs = getText(R.string.styled_text); tv = (TextView)findViewById(R.id.styled_text); tv.setText(cs); // Use the same resource, but convert it to a string, which causes it // to lose the style information. str = getString(R.string.styled_text); tv = (TextView)findViewById(R.id.plain_text); tv.setText(str); // Using the Resources object // You might need to do this if your code is not in an activity. // For example View has a protected mContext field you can use. // In this case it's just 'this' since Activity is a context. Context context = this; // Get the Resources object from our context Resources res = context.getResources(); // Get the string resource, like above. cs = res.getText(R.string.styled_text); tv = (TextView)findViewById(R.id.res1); tv.setText(cs); // Note that the Resources class has methods like getColor(), // getDimen(), getDrawable() because themes are stored in resources. // You can use them, but you might want to take a look at the view // examples to see how to make custom widgets. } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/styled_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textStyle="normal" /> <TextView android:id="@+id/plain_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textStyle="normal" /> <TextView android:id="@+id/res1" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textStyle="normal" /> </LinearLayout>
Need the following import to get access to the app resources, since this class is in a sub-package.
package com.example.android.apis.view; import android.app.Activity; import android.database.Cursor; import android.provider.ContactsContract.Contacts; import android.os.Bundle; import android.widget.Gallery; import android.widget.SimpleCursorAdapter; import android.widget.SpinnerAdapter; // Need the following import to get access to the app resources, since this // class is in a sub-package. import com.example.android.apis.R; public class Gallery2 extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gallery_2); // Get a cursor with all people Cursor c = getContentResolver().query(Contacts.CONTENT_URI, CONTACT_PROJECTION, null, null, null); startManagingCursor(c); SpinnerAdapter adapter = new SimpleCursorAdapter(this, // Use a template that displays a text view android.R.layout.simple_gallery_item, // Give the cursor to the list adatper c, // Map the NAME column in the people database to... new String[] {Contacts.DISPLAY_NAME}, // The "text1" view defined in the XML template new int[] { android.R.id.text1 }); Gallery g = (Gallery) findViewById(R.id.gallery); g.setAdapter(adapter); } private static final String[] CONTACT_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME }; } //gallery_2.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginBottom="10dip" android:text="gallery_2_text" /> <Gallery android:id="@+id/gallery" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:spacing="16dp" /> </LinearLayout>
Demonstration of styled text resources.
package com.example.android.apis.content; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Demonstration of styled text resources. */ public class ExternalStorage extends Activity { ViewGroup mLayout; static class Item { View mRoot; Button mCreate; Button mDelete; } Item mExternalStoragePublicPicture; Item mExternalStoragePrivatePicture; Item mExternalStoragePrivateFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.external_storage); mLayout = (ViewGroup)findViewById(R.id.layout); mExternalStoragePublicPicture = createStorageControls( "Picture: getExternalStoragePublicDirectory", Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), new View.OnClickListener() { public void onClick(View v) { createExternalStoragePublicPicture(); updateExternalStorageState(); } }, new View.OnClickListener() { public void onClick(View v) { deleteExternalStoragePublicPicture(); updateExternalStorageState(); } }); mLayout.addView(mExternalStoragePublicPicture.mRoot); mExternalStoragePrivatePicture = createStorageControls( "Picture getExternalFilesDir", getExternalFilesDir(Environment.DIRECTORY_PICTURES), new View.OnClickListener() { public void onClick(View v) { createExternalStoragePrivatePicture(); updateExternalStorageState(); } }, new View.OnClickListener() { public void onClick(View v) { deleteExternalStoragePrivatePicture(); updateExternalStorageState(); } }); mLayout.addView(mExternalStoragePrivatePicture.mRoot); mExternalStoragePrivateFile = createStorageControls( "File getExternalFilesDir", getExternalFilesDir(null), new View.OnClickListener() { public void onClick(View v) { createExternalStoragePrivateFile(); updateExternalStorageState(); } }, new View.OnClickListener() { public void onClick(View v) { deleteExternalStoragePrivateFile(); updateExternalStorageState(); } }); mLayout.addView(mExternalStoragePrivateFile.mRoot); startWatchingExternalStorage(); } @Override protected void onDestroy() { super.onDestroy(); stopWatchingExternalStorage(); } void handleExternalStorageState(boolean available, boolean writeable) { boolean has = hasExternalStoragePublicPicture(); mExternalStoragePublicPicture.mCreate.setEnabled(writeable && !has); mExternalStoragePublicPicture.mDelete.setEnabled(writeable && has); has = hasExternalStoragePrivatePicture(); mExternalStoragePrivatePicture.mCreate.setEnabled(writeable && !has); mExternalStoragePrivatePicture.mDelete.setEnabled(writeable && has); has = hasExternalStoragePrivateFile(); mExternalStoragePrivateFile.mCreate.setEnabled(writeable && !has); mExternalStoragePrivateFile.mDelete.setEnabled(writeable && has); } BroadcastReceiver mExternalStorageReceiver; boolean mExternalStorageAvailable = false; boolean mExternalStorageWriteable = false; void updateExternalStorageState() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { mExternalStorageAvailable = mExternalStorageWriteable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { mExternalStorageAvailable = true; mExternalStorageWriteable = false; } else { mExternalStorageAvailable = mExternalStorageWriteable = false; } handleExternalStorageState(mExternalStorageAvailable, mExternalStorageWriteable); } void startWatchingExternalStorage() { mExternalStorageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i("test", "Storage: " + intent.getData()); updateExternalStorageState(); } }; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_MOUNTED); filter.addAction(Intent.ACTION_MEDIA_REMOVED); registerReceiver(mExternalStorageReceiver, filter); updateExternalStorageState(); } void stopWatchingExternalStorage() { unregisterReceiver(mExternalStorageReceiver); } void createExternalStoragePublicPicture() { // Create a path where we will place our picture in the user's // public pictures directory. Note that you should be careful about // what you place here, since the user often manages these files. For // pictures and other media owned by the application, consider // Context.getExternalMediaDir(). File path = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); try { // Make sure the Pictures directory exists. path.mkdirs(); // Very simple code to copy a picture from the application's // resource into the external file. Note that this code does // no error checking, and assumes the picture is small (does not // try to copy it in chunks). Note that if external storage is // not currently mounted this will silently fail. InputStream is = getResources().openRawResource(R.drawable.balloons); OutputStream os = new FileOutputStream(file); byte[] data = new byte[is.available()]; is.read(data); os.write(data); is.close(); os.close(); // Tell the media scanner about the new file so that it is // immediately available to the user. MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Log.i("ExternalStorage", "Scanned " + path + ":"); Log.i("ExternalStorage", "-> uri=" + uri); } }); } catch (IOException e) { // Unable to create file, likely because external storage is // not currently mounted. Log.w("ExternalStorage", "Error writing " + file, e); } } void deleteExternalStoragePublicPicture() { // Create a path where we will place our picture in the user's // public pictures directory and delete the file. If external // storage is not currently mounted this will fail. File path = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); file.delete(); } boolean hasExternalStoragePublicPicture() { // Create a path where we will place our picture in the user's // public pictures directory and check if the file exists. If // external storage is not currently mounted this will think the // picture doesn't exist. File path = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); return file.exists(); } void createExternalStoragePrivatePicture() { // Create a path where we will place our picture in our own private // pictures directory. Note that we don't really need to place a // picture in DIRECTORY_PICTURES, since the media scanner will see // all media in these directories; this may be useful with other // media types such as DIRECTORY_MUSIC however to help it classify // your media for display to the user. File path = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File file = new File(path, "DemoPicture.jpg"); try { // Very simple code to copy a picture from the application's // resource into the external file. Note that this code does // no error checking, and assumes the picture is small (does not // try to copy it in chunks). Note that if external storage is // not currently mounted this will silently fail. InputStream is = getResources().openRawResource(R.drawable.balloons); OutputStream os = new FileOutputStream(file); byte[] data = new byte[is.available()]; is.read(data); os.write(data); is.close(); os.close(); // Tell the media scanner about the new file so that it is // immediately available to the user. MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Log.i("ExternalStorage", "Scanned " + path + ":"); Log.i("ExternalStorage", "-> uri=" + uri); } }); } catch (IOException e) { // Unable to create file, likely because external storage is // not currently mounted. Log.w("ExternalStorage", "Error writing " + file, e); } } void deleteExternalStoragePrivatePicture() { // Create a path where we will place our picture in the user's // public pictures directory and delete the file. If external // storage is not currently mounted this will fail. File path = getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (path != null) { File file = new File(path, "DemoPicture.jpg"); file.delete(); } } boolean hasExternalStoragePrivatePicture() { // Create a path where we will place our picture in the user's // public pictures directory and check if the file exists. If // external storage is not currently mounted this will think the // picture doesn't exist. File path = getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (path != null) { File file = new File(path, "DemoPicture.jpg"); return file.exists(); } return false; } void createExternalStoragePrivateFile() { // Create a path where we will place our private file on external // storage. File file = new File(getExternalFilesDir(null), "DemoFile.jpg"); try { // Very simple code to copy a picture from the application's // resource into the external file. Note that this code does // no error checking, and assumes the picture is small (does not // try to copy it in chunks). Note that if external storage is // not currently mounted this will silently fail. InputStream is = getResources().openRawResource(R.drawable.balloons); OutputStream os = new FileOutputStream(file); byte[] data = new byte[is.available()]; is.read(data); os.write(data); is.close(); os.close(); } catch (IOException e) { // Unable to create file, likely because external storage is // not currently mounted. Log.w("ExternalStorage", "Error writing " + file, e); } } void deleteExternalStoragePrivateFile() { // Get path for the file on external storage. If external // storage is not currently mounted this will fail. File file = new File(getExternalFilesDir(null), "DemoFile.jpg"); if (file != null) { file.delete(); } } boolean hasExternalStoragePrivateFile() { // Get path for the file on external storage. If external // storage is not currently mounted this will fail. File file = new File(getExternalFilesDir(null), "DemoFile.jpg"); if (file != null) { return file.exists(); } return false; } Item createStorageControls(CharSequence label, File path, View.OnClickListener createClick, View.OnClickListener deleteClick) { LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE); Item item = new Item(); item.mRoot = inflater.inflate(R.layout.external_storage_item, null); TextView tv = (TextView)item.mRoot.findViewById(R.id.label); tv.setText(label); if (path != null) { tv = (TextView)item.mRoot.findViewById(R.id.path); tv.setText(path.toString()); } item.mCreate = (Button)item.mRoot.findViewById(R.id.create); item.mCreate.setOnClickListener(createClick); item.mDelete = (Button)item.mRoot.findViewById(R.id.delete); item.mDelete.setOnClickListener(deleteClick); return item; } } //layout/external_storage.xml <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="none"> <LinearLayout android:id="@+id/layout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> </LinearLayout> </ScrollView> //layout/external_storage_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/label" style="?android:attr/textAppearanceMediumInverse" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:padding="4dip" android:singleLine="true" android:color="?android:attr/textColorPrimaryInverse" android:background="#888" /> <TextView android:id="@+id/path" style="?android:attr/textAppearanceSmall" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:padding="4dip" android:singleLine="true" /> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <View android:layout_width="0dip" android:layout_height="0dip" android:layout_weight="1" /> <Button android:id="@+id/create" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/create" /> <View android:layout_width="0dip" android:layout_height="0dip" android:layout_weight="1" /> <Button android:id="@+id/delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/delete" /> <View android:layout_width="0dip" android:layout_height="0dip" android:layout_weight="1" /> </LinearLayout> </LinearLayout>
Demonstrates using -wNNNdp and -hNNNdp resource configs.
package com.example.android.apis.content; import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; public class ResourcesSmallestWidth extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // This layout uses different configurations to adjust // what is shown based on the smallest width that will occur. setContentView(R.layout.resources_smallest_width); } } //layout/resources_smallest_width.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:gravity="center_horizontal" android:paddingTop="8dp" android:paddingBottom="8dp" android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/resources_smallest_width_description"/> <FrameLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1" android:background="@android:drawable/gallery_thumb"> <include layout="@layout/resources_smallest_width_inner" /> </FrameLayout> </LinearLayout>
Resources width and height
package com.example.android.apis.content; import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; public class ResourcesWidthAndHeight extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // This layout uses different configurations to adjust // what is shown based on the current screen width and height. setContentView(R.layout.resources_width_and_height); } } //layout/resources_width_and_height.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" android:gravity="center_horizontal" android:paddingTop="8dp" android:paddingBottom="8dp" android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/resources_width_and_height_description"/> <FrameLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1" android:background="@android:drawable/gallery_thumb"> <include layout="@layout/resources_height" /> </FrameLayout> </LinearLayout>
Load resource
//package org.andlib.helpers; import java.io.InputStream; import android.app.Activity; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; final class ResourceHelper { /** * get resource id from given name and type * * @param context * @param name resource's name (without extension) * @param type type of resource (ex: "drawable", "raw", ...) * @return 0 if fails */ public static int getResourceId(Context context, String name, String type) { return context.getResources().getIdentifier(name, type, context.getPackageName()); } /** * * @param context * @param resourceId * @return null if fails */ public static InputStream getResourceAsInputStream(Context context, int resourceId) { try { return context.getResources().openRawResource(resourceId); } catch(Exception e) { // Logger.e(e.toString()); } return null; } /** * * @param context * @param name of resource (without extension) * @param type of resource (ex: "drawable", "raw", ...) * @return null if fails */ public static InputStream getResourceAsInputStream(Context context, String name, String type) { try { return context.getResources().openRawResource(getResourceId(context, name, type)); } catch(Exception e) { // Logger.e(e.toString()); } return null; } /** * * @param context * @param resourceId * @return null if fails */ public static AssetFileDescriptor getResourceAsFd(Context context, int resourceId) { try { return context.getResources().openRawResourceFd(resourceId); } catch(Exception e) { // Logger.e(e.toString()); } return null; } /** * * @param context * @param name of resource (without extension) * @param type of resource (ex: "drawable", "raw", ...) * @return null if fails */ public static AssetFileDescriptor getResourceAsFd(Context context, String name, String type) { try { return context.getResources().openRawResourceFd(getResourceId(context, name, type)); } catch(Exception e) { // Logger.e(e.toString()); } return null; } /** * get filepath of given content uri * * @param activity * @param contentUri * @return null if fails */ public static String getFilepathOfUri(Activity activity, Uri contentUri) { Cursor cursor = activity.managedQuery(contentUri, new String[]{MediaStore.Images.Media.DATA}, null, null, null); try { int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(index); } catch(Exception e) { //Logger.e(e.toString()); } return null; } }