Posts

Showing posts from 2010

Playing with lists in Android - Part II

Image
I hope you already read my first topic about listView. In part II, I am just extending the part I topic. So please read part I before reading part II.

In this, I am creating an adapter, in which each list item consists of two views, a TextView and an IMageView respectively. I am putting these two views in a relative layout. Then I am aligning the imageView to the right end of the layout using the addRule(). One more thing is, here I am putting a static image, that is the standard Android icon.

The adapter class is,



class MyAdapter extends BaseAdapter {

Context mContext;

public MyAdapter(Context context) {
mContext = context;
}

public int getCount() {
return list.size();
}

public Object getItem(int id) {
return id;
}

public long getItemId(int position) {
return position;
}

public View getView(int position, View convertView, ViewGroup parent) {
RelativeLayout layout = new RelativeLayout(mContext);

android.wi…

Some Android Tips

Image
If we connect the device and if it show offline in DDMS, from the options menu click "Reset ADB" or from command prompt first execute "adb kill-server". After executing that execute "adb start-server"

Playing with Lists in Android - Part I

Image
In this tutorial, first I am going to show you a simple but useful tutorial on ListView in Android.

Whatever we are entering in the editText will be shown in the list, like a starting for chat application UI.

Things required for this are ListView, adapter, arrayList, editText and a button. I created the layout in XML, as this is a small UI with few components. Another reason for this is, for my few previous projects, I need to use java for creating layouts.

The complete code will look like this..



public class SampleListView_Chat extends Activity {

ListView lView;
ArrayList list;
EditText eText;
Button but;
ArrayAdapter adapter;
LinearLayout layout, subLayout;
LayoutParams params, lParams;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
subLayout = new LinearLayout(this);
params = new LayoutParams(LayoutParams.WRAP_CONTEN…

Creating shortcuts through Intent in Android

Image
We can create shortcut for an application through intent. Its not so difficult. First create an intent with the package name of the application and add some flags to it. Then create another intent and add the first intent to it as extras and broadcast the intent. That is it.

The complete code is,



public class CreateShortcut extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent shortcutIntent = new Intent();
Log.i("CreateShortcut", "Creating first intent called shortcutIntent");
shortcutIntent.setClassName(getPackageName(), "CreateShortcut");
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent intent = new Intent();
Log.i("CreateShortcut", "Creating intent for broadcasting");
intent.putExtra(Intent.…

Creating LiveFolder in Android

Image
In Android, a live folder is simply a real-time view of a ContentProvider. LiveFolder allow displaying of data on home screen without launching the application.



public class CreateLiveFolder extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri = Browser.BOOKMARKS_URI;
final Intent intent = getIntent();
final String action = intent.getAction();
if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
setResult(RESULT_OK, createLiveFolder(this, uri,
"Books", R.drawable.icon));
} else {
setResult(RESULT_CANCELED);
}
finish();
}

private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) {
final Intent intent = new Intent();
intent.setData(uri);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOL…

Opening Contacts, Gallery and other system applications through Intent in Android

Image
Code snippets for opening contacts, gallery etc through intent


// opening Contact
Intent intent = new Intent(Intent.ACTION_PICK, People.CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE);




// opening Gallery
Intent i = new Intent(Intent.ACTION_PICK);
i.setType("image/*");
startActivityForResult(i, 1);



// opening All
Intent i = new Intent(Intent.ACTION_PICK);
i.setType("*/*");
startActivityForResult(i, 1);


By setting the type of the intent object to image/*, gallery will display, accordingly if we put corresponding action and data , we can display SMS, settings page etc.

If we put the data of intent as "*/*", a pop-up will display, which shows the available list of the applications that can display.

The screen shot is,

Live Wallpaper in Android

Live wallpaper is richer, animated, interactive backgrounds on the home screen of Android devices. A live wallpaper is very similar to a normal Android application and has access to all the facilities of the platform: SGL (2D drawing), OpenGL (3D drawing), GPS, accelerometers, network access, etc.

A live wallpaper is very similar to a regular Android service. The only difference is the addition of a new method, onCreateEngine() whose goal is to create a WallpaperService.Engine. The engine is responsible for handling the lifecycle and the drawing of a wallpaper.

Here, I am showing a general method for creating Live Wallpaper. According to our requirement or to our wish, we can draw some image when we touch anywhere on the screen, or according to the time, we can set different images like for morning from 6AM to 12PM, then 12PM to 6PM another image like that. or according to the location, we can set some image. In office one image, in home, another image like that.

First thing for creating…

Uninstalling installed applications using Intent in Android

Image
To uninstall the install application using Intent, the code snippet is

Intent intent = new Intent(Intent.ACTION_DELETE); intent.setData(Uri.parse("package:com.example.android.apis")); startActivity(intent);

The screenshot is,

Getting List of Installed Applications in Android

Image
We can get the list of android applications that is installed in the android device through PacketManager and using the API queryIntentActivities(). To get the list of installed applications in the device,

The complete code snippet is,


public class AppList extends Activity {
private ListView lView;
private ArrayList results = new ArrayList();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lView = (ListView) findViewById(R.id.list1);
PackageManager pm = this.getPackageManager();

Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);

List list = pm.queryIntentActivities(intent, PackageManager.PERMISSION_GRANTED);
for (ResolveInfo rInfo : list) {
results.add(rInfo.activityInfo.applicationInfo
.loadLabel(pm).toString());
Log.w("Installed Applications", rInfo.activityInfo.applicationInfo
.loadLabel(pm).toString());
}
lView.setAdapter(ne…

Listening to Phone calls using PhoneStateListener

Image
When an incoming call is coming to your mobile, you can get the number of the incoming call, through the interface phoneStateListener. Then we can also get the state the mobile phone throught the same phoneStateListener. Here, I used two emulators to show the scenario.

For this, first install the application in two emulators.

The complete code is,


public class CaptureCall extends Activity {

TelephonyManager tm;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
tm.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}

private PhoneStateListener mPhoneListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
try {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(CaptureCall.this, "CALL_STATE_RINGING", Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFH…

Read Package information from Manifest in Android

We can get the package name, version number, version code, permissions, META-DATA like what ever we faced placed in the manifest file can be retrieved using PackageManager.

The code snippet is,


public class ReadPackage extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Read package name and version number from manifest
try {
PackageManager manager = this.getPackageManager();
PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
Toast.makeText(
this,
"PackageName = " + info.packageName + "\nVersionCode = "
+ info.versionCode + "\nVersionName = "
+ info.versionName + "\nPermissions = "+info.permissions, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
System.out.println(" Exception in onCreate() : e = " + e);
}
}
}

Showing Route through Google Map in Android

Image
To show the route between two places in google map, we can use

"http://maps.google.com/maps?&saddr=13.042206,80.17000&daddr=9.580000,78.100000"

this url.

Here I used the latitude and longitude of Chennai and Madurai, two cities in India.

The complete code snippet is,



public class LaunchMap extends MapActivity {

Uri uri;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uri =Uri.parse("http://maps.google.com/maps?&saddr=13.042206,80.17000&daddr=9.580000,78.100000");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
finish();
}

@Override
protected boolean isRouteDisplayed() {
return false;
}
}



For showing this, we need to include the google map library in Manifest file.

A the time of launching , a pop up will ask to open in Browser or Google maps, just click on google map and it will show a list displaying the step by step direction as,



If we click on the list item …

Live Audio streaming using MediaPlayer in Android

Live Audio streaming in android, from 1.6 sdk onwards is become so easy. In setDataSource() API directly pass the url and audio will play without any issues.

The complete code snippet is,


public class AudioStream extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url = "http://www.songblasts.com/songs/hindi/t/three-idiots/01-Aal_Izz_Well-(SongsBlasts.Com).mp3";
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(url);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
mp.start();
} catch (Exception e) {
Log.i("Exception", "Exception in streaming mediaplayer e = " + e);
}
}
}


The Url I used here is a song from a bollywood film 3 Idiots.


Happy Coding

Creating SDCard and using it in emulator

The command for creating sdcard is

mksdcard 16M image.iso

Here we created a sdcard of name "image" with 16MB of size.

For using the sdcard in emulator, give this command

-sdcard /image.iso

in "Additional Emulator Command Line Options"

INSTALL_PARSE_FAILED_NO_CERTIFICATES in Android

Today, when I am doing a project in Android, suddenly I got this error. Actually, when I got this error is, after putting a png file in drawable called "close_btn_nmb". After putting this png file and try to run, I got tINSTALL_PARSE_FAILED_NO_CERTIFICATES error in 1.6 SDK. After some googling, I just renamed the file as, "close_btnnmb" and it worked fine. At that time, I came to know about Issue-830

So, when giving name to drawable files, try to avoid, two underscores. This is not a hard core rule, just my insight.

File Browser in Andriod

Image
File browser in android is used to access the internal file system in Android. Through the file browser, we can browse through the files. The features are

- sorting,
- size of the file
- an icon to recognize the file or directory
- open the file, if permission is there.

Then a Home button, to come to the root directory, SDcard button, to show sdcard files. A back button is always there, if the parent directory is not null.

For opening the file, there is function, I created called openFile(), in that, according to the extension of the file, I am setting the MIME type for intent using the API called setDataAndType(). The android file system contains lot of file types like audio, video, text, (text itself contain html, php, xml, csv etc).

Another important method(API), is listFiles(). This will return an array of files and this array, we are passing to the fill() in the FileBrowser class. We will check a file is a directory or not using isDirectory()


The code for openFile() which is an very i…

Launching Google Map using Intent in Android

Image
Using intent we can open google map. The URI for launching google map is geo:13.042206,80.17000?z=10

The complete code snippet is,



double latitude = 13.042206;
double longitude = 80.17000;
uri = Uri.parse("geo:" + latitude + "," + longitude +"?z=10");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);


The latitude and longitude , I specified here is for Chennai. We can also specify the zoom level. Here I specified the zoom level as 10.

The screenshot is,



From the menu you will get all the options that are available in google map as,

Vibration in Android

The code snippet for vibrating android phone is,


Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(2000);


Here 2000 is 2000 milliseconds, the phone will vibrate. And of course you can't test this in emulator, you need a real device to test this.

Opening an Application using Intent

In Android, if we know the package name and the activity which is launching the application, we can open or launch the application from anywhere using Intent.

The code snippet is,


Intent intent = new Intent("android.intent.action.MAIN");
ComponentName component = new ComponentName("com.sample", "com.sample.Sample");
intent.setComponent(component );
startActivity(intent);

Manufacturer Name and phone model in Android

To get the manufacturer name and other details about the android phone, we can use the class called android.os.Build

To get the manufacturer name use, Build.MANUFACTURER
To get the phone model use, Build.MODEL

Accelerometer Sensor in Android

Android phones has lot of sensors. In this, I am showing you the how accelerometer sensor works. Accelerometer will show you thew x, y and z co-ordinates of your phone movement. Actually, this sensor, we used in one of our application. In that, when shake the phone horizontally, doing some action. So like this, you can also do according to the values you get from the onSensorChanged() in SensorEventListener interface.

The complete code is,

AndAccelorometer.java public class AndAccelorometer extends Activity implements SensorEventListener { SensorManager sMgr; Sensor accelrometerSensor; @Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE); accelrometerSensor = sMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sMgr.registerListener(this, accelrometerSensor, SensorManager.SENSOR_DELAY_UI); } public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-gener…

Opening Camera from Application

The basic things for augmented reality are camera, Sensor to know the direction, and the GPS or network provider to get the current location details. Gradually, I will show you the Augmented Reality in Android. In this, showing you how to open a camera from application.

CameraPreview.java



class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

SurfaceHolder holder;
Camera camera;

public CameraPreview(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

@Override
public void surfaceChanged(SurfaceHolder holder2, int format, int w,
int h) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(w, h);
camera.setParameters(parameters);
camera.startPreview();
}

@Override
public void surfaceCreated(SurfaceHolder holder1) {
try {
camera = Camera.open();
camera.setPreviewDisplay(holder1);
} catch (Exception e) {
Log.i(&…

HTTP 100 Conitnue Error in Android

When I am doing a project in Android suddenly, I got this error "HTTP 100 conitnue" when sending request to server and I am not getting the proper response from the server. After some googling, I came to know about one API, and I want to share with all about that. It is setUseExpectContinue()

The complete code snippet is,


HttpProtocolParams.setUseExpectContinue(client.getParams(), false);

Here, client is an object of "HttpClient"

After using this code snippet, I got proper response from server and all work fine.

Happy Coding

Different ways for Notifying Users in Android

Image
The 3 main different ways to notify an user are,

Dialog
Toast
Notification

Dialog

For notifying users with dialog, We will create an object of dialog. In this, I am removing the title using requestWindowFeature(Window.FEATURE_NO_TITLE) and adding a layout to the dialog to it using addContentView().

Toast

Second one is toast, that will flash and will display for a predefined period either as, Toast.LENGTH_SHORT or Toast.LENGTH_LONG.

Notification

Third one is notification, to notify user, about any background activity is started.

The complete sample programs is,


public class NotifyUser extends Activity {

LayoutParams panelParams, compParams, tvParams;
LinearLayout popupGrid;
LinearLayout buttonLayout;
TextView tv;
Button b1, b2;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
displayDialog();
displayToast();
displayNotification();
}

public void displayDialog() {
Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TIT…

Data Storage in Android

The storage system in Android are mainly divided into 3 types.

Database(sqlite)
File
SharedPreference

Database is already explained in my older post and you can see here

Files

Android can save files directly to the device internal storage. These files are private to the application and will be removed if you uninstall the application.

We can create a file using openFileOutput() with parameters as file name and the operating mode. Similarly, we can open the file using openFileInput() passing the parameter as the fileName. One thing, that we need to remeber is, give the file name with extension. In this example I am creating a text(.txt) file.

The complete code is,


public class ReadNWriteFile extends Activity {

final String TEST_STRING = new String("Hello Android");
final String FILE_NAME = "SAMPLEFILE.txt";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
fileCreate();
tv.setText(readFile())…

Scrolling of TextView

Code Snippet for scrolling textview is

TextView tv;
tv.setMovementMethod(ScrollingMovementMethod.getInstance());

TabActivity in Android

Tabs can be created in Android, in a number of ways. I am going to create using Java only. I don't want to use xml and I want my tab content should be dynamic. So, I am implementing Tabs through TabHost.TabContentFactory. This interface has an abstract method called createTabContent() and it will return a View.

Another interesting fact , I came to know is, Tabs can be created without TabActivity too. Thats a new information for me. I came to know this through a discussion in Android Developers google group. If you are interested you can see the complete discussion here

The complete code for this is,


public class SampleTab extends Activity implements TabHost.TabContentFactory {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

TabHost tabHost = new TabHost(SampleTab.this);
TabWidget tabW = new TabWidget(this);
FrameLayout frame = new FrameLayout(this);
frame.setId(android.R.id.tabcontent);
tabW.addView(frame);
tabW.setId(android.R.…

ExpandableListActivity in Android

Image
I want to use expandablelist activity, when I want to show two lists in a single screen like a main list and a sub-list. For example, a list of countries are there(Main list) and I want to show the main cities(sub-list) of theses countries. In that case, expandable list activity will be very useful. This is just one use of expandable list. Like that it can use for hundreds of purposes.

The complete code is,


public class CountryStateList extends ExpandableListActivity {

private static final String NAME = "NAME";
private static final String IS_EVEN = "IS_EVEN";
private ExpandableListAdapter mAdapter;
List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
InputStream is;
boolean addState = true;
boolean addCountry;
HashMap<String, String> countryMap = new HashMap<String, String>();
HashMap<…

AlarmManager and Notification in Android

Image
In this, I am going to explain AlarmManager and Notification. For Notifying Users in Android, we can use mainly 3 methods as,

Dialog
Toast
Notification

The full picture of this can seen here

AlarmManager, we can use in two ways, as

-To start some action, if a particular event happens,
-To do some particular actions in every time interval.

As specified in Android developer site, we will use AlarmManager, when we need to do some actions, even if our application is not running. For normal timing operations use handlers.

For using AlaramManager, first we need to declare the BroadcastReceiver in Manifest file as,

<receiver android:name=".TimeAlarm" />
We need to get the object of the AlarmManager using getSystemService(), then define an intent with parameters as the current context and the BoradcastReceiver class(TimeAlarm). Then define a pendingIntent, we will get the object of it using PendingIntent.getBroadcast(). Now we can call the set() of AlarmManager for doing some ac…

AsyncTask in Android

AsyncTask allows us to do proper background operations without creating threads and handlers. AsyncTask will run in the background thread and whose results we can pass to the UI thread. To implement AsyncTask, what we need to do is, create a class which extends AsyncTask and need to override some methods in it like doInBackground(), onPostExecute(), onProgressUpdate().

Sample program is,


private class BackgroundTask extends AsyncTask {

@Override
protected Void doInBackground(Void... params) {
}
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
protected void onProgressUpdate(Integer... progress) {
}

}


We can call AsyncTask using, new BackgroundTask().execute();

Fetching IMEI number in Android

We can fetch the IMEI number of android phones using,


TelephonyManager mTelephonyMgr = (TelephonyManager)
getSystemService(Context.TELEPHONY_SERVICE);
String imei = mTelephonyMgr.getDeviceId();

ContentProvider in Android

I already told about the built-in content-providers in Android, in one of my tutorial

In this, I am creating a new custom content provider. For this, first we will declare the content provider in Manifest file as,

<provider android:name="Provider" android:authorities="simple.provider"/>

So,Provider is my content provider name. Created a class called Provider which extends ContentProvider. The CONTENT_URI, which I am going to use is, "content://simple.provider/mytable"

The complete source code is,

Provider.java


public class Provider extends ContentProvider {

public static final String AUTHORITY = "simple.provider";
// public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
// + "/table1");
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/mytable");
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.provider.mytable";
public static …

ViewStub in Android

Image
In this, I just going to show how to use ViewStub in Android. Once again, I am telling this is just a very basic tutorial for ViewStub.

The complete code is,

SampleViewStub.java


public class SampleViewStub extends Activity {

ViewStub stub;
boolean click = true;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.openstub).setOnClickListener(new OnClickListener() {

public void onClick(View v) {
if (click) {
stub = (ViewStub) findViewById(R.id.stub1);
stub.inflate();
click = false;
}
}
});
}
}


main.xml


<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:l…

Swipe Action and ViewFlipper in Android

Last tutorial I talked about ViewFlipper, in this I am just extending the functonality of ViewFlipper with swipe action. ViewFlipper is mainly used to animate views. I have two or three views added to the ViewFlipper and using the API showNext() and showPrevious(), we can show the next and previous view in the ViewFlipper. At the time of switching, we can create some animation and it looks great.

Foe switching between views, we can either use time interval or through user interaction. Last tutorial I used button for switching between Views. In this tutorial I am going to use swipe action for switching views.

class MyGestureDetector extends SimpleOnGestureListener { private static final int SWIPE_MIN_DISTANCE = 120; private static final int SWIPE_MAX_OFF_PATH = 250; private static final int SWIPE_THRESHOLD_VELOCITY = 200; public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { System.out.println(" in onFling() :: "); if (Ma…

Changing layout height dynamically

We can change the layout height dynamically to say, x by using

getLayoutParams().height= x;
requestLayout(); or invalidate();

ViewFlipper in Android

ViewFlipper is used to do animation when switching between views. There are lot of options for doing animations between views like ViewAnimator, LayoutAnimationController, applying animation to the view itself. But I feel ViewFlipper is the better option for doing animation for switching views.

In this I am controlling the switching between views using user interaction(Button click). We can set duration also for switching between views.

The complete code for showing ViewFlipper is,


public class ShowFlipper extends Activity {

ViewFlipper flipper;
Button button1;
Button button2;
LinearLayout l1;
LinearLayout l2;
TextView tv1, tv2, tv3, tv4, tv5, tv6;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);

flipper = new ViewFlipper(this);
l1 = new LinearLayout(this);
l2 = new LinearLayout(this);
button1 = new Button(this);
button2 = new Button(thi…