quarta-feira, 27 de março de 2013

Image Downloader

Hello people,

This post demonstrates like to use the DownloadManager class available in Android SDK. This class is very powerful and enable us to download files from Internet to our device. Our application will have a main screen with one CheckBox to define whether our downloads will be done only if a WI-FI connection be available and one Button that starts the download. The other activity will be called when the notification area is clicked and will show the filename name and to enable cancelling the download.

You will see at this post:

  • Writing in shared preferences
  • Downloading a file
  • File System

The code used in this post can be downloaded here.

At first, is necessary to write the permissions on the manifest file.


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

I believe that these permissions are very easy to understand, because their names are very deductible.

I created a BroadcastReceiver to receiver all download notifications. Purposely, I registered the receiver on the manifest, so, even that our application is closed, it will be called when the user click on the notification area. When the user clicks on the notification area, the download id is retrieved and checked whether it was started by our application.


@Override
public void onReceive(Context context, Intent intent) {
if (!checkDownloadID(context))
return;
String action = intent.getAction();
if (action == DownloadManager.ACTION_DOWNLOAD_COMPLETE)
downloadCompletedOrCancelled(context, intent);
if (action == DownloadManager.ACTION_NOTIFICATION_CLICKED)
downloadNotificationClicked(context, intent);

}



private void downloadNotificationClicked(Context context, Intent intent) {

String extraID = DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS;
long[] references = intent.getLongArrayExtra(extraID);
for (long reference : references) {
Intent intentDownloadDetails = new Intent(context,
DownloadDetailsActivity.class);
Bundle bundle = new Bundle();
bundle.putLong(General.EXTRA_DOWNLOAD_ID_KEY, reference);
intentDownloadDetails.putExtras(bundle);
intentDownloadDetails.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentDownloadDetails);
}
}


Note that the DownloadDetailsActivity is called when the notification area is clicked by the user.

When the user starts a new download on the MainActivity, the download id is stored on the preferences. It is used when our application starts, to check if the download manager is controlling a download from our application.

The code block below is very interesting because it has a lot of important tips. I commented this code purposely.


buttonStartDownload.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
if (!checkConnection())
return;

// create a downloadManager reference and sets it...
// DownloadManager downloadManager;
DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new Request(Uri.parse(url));

if (checkBoxDownloadWifiOnly.isChecked())
request.setAllowedNetworkTypes(Request.NETWORK_WIFI);

// allows that the file be scanned by media scanner...
request.allowScanningByMediaScanner();

//set the details of notification area...
request.setTitle(getResources().getText(R.string.downloadImage));
request.setDescription(getResources().getText(
R.string.nasaImageForDownload));

// saves the image on the public directory of pictures...
request.setDestinationInExternalPublicDir(
Environment.DIRECTORY_PICTURES, "image.jpg");

// disables the controls...
buttonStartDownload.setEnabled(false);
checkBoxDownloadWifiOnly.setEnabled(false);

// starts the download and use the shared preferences to persist
// its key.
long reference = downloadManager.enqueue(request);
Editor editor = preferences.edit();
editor.putLong(General.PREFERENCE_DOWNLOAD_ID_KEY, reference);
editor.apply();

// finishes the activity...
finish();

}
});

I believe that you may download the code and run it.

Good luck!




terça-feira, 12 de março de 2013

Creating a currency converter application

Hello people,

There's a long time since the last post, but I have a lot of new things to show here. In the last posts, I wrote about specifics subjects, but today I'll write about a lot of subjects  while we build a application.
Like this post title said, we will build a application that will to convert a currency to other. For this we will approach:


  • Internet resources
  • Network State
  • Shared Preferences
  • Preferences Framework
  • Broadcasts and Receivers


You can download this application clicking here.

Our application will have a principal screen, where the user can see the base currency and the other currencies with yours respective conversion rates.

Furthermore, the user can modify the program settings, choosing the base currency, the currencies that will be converted and the interval between screen refreshes.

First of all, we will see the AndroidManifest.xml. There, we must have declare the permissions used by our application. If we don't declare this permissions our application can not be executed.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

We will use the android.permission.INTERNET when our application to request a URL and we will use android.permission.ACCESS_NETWORK_STATE to receive broadcasts when network state change.

I won't explain each class contained in this project, but it's very important to know some them.

ConnectivityMonitorReceiver to MainActivity


I built this class to manage the connection state. This class is a extension from a BroadcastReceiver class and its function is receive the broadcast with the connection state and send a broadcast to application with the treated connection state information. I did the integration between this class and the application by broadcasts interchanging.

The MainActivity has a registred receiver to handle the connection state. When the MainActivity receives the broadcast automatically is showed in a textView the connection state.

CurrencyAsyncTask to MainActivity


The CurrencyAsyncTask class has been built to execute asynchronous actions on  Internet. When it is need to do a request to Internet is need execute this action in a separate thread, otherwise a exception of type NetworkOnMainThreadException will be thrown. This class extends AsyncTask and after the main action is executed, a broadcast is sent to application with all data related a specific currency.

In this class, the two most important points are the code used to access Internet information and the fact of this class be executed in a separated thread due be extended from AsyncTask.

See this code below, overriding doInBackground we can put Internet requests here:

@Override
protected String doInBackground(String... args) {

// get parameters passed...
String fromCurrency = args[0];
String toCurrency = args[1];

// set the url from service passing parameters values...
String urlstring = "http://currencies.apps.grandtrunk.net/getlatest/";
urlstring += fromCurrency + "/";
urlstring += toCurrency;

// creates URL object to retrieve data...
URL url;
try {
url = new URL(urlstring);

URLConnection connection;
connection = url.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;

int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = httpConnection.getInputStream();

BufferedReader r = new BufferedReader(new InputStreamReader(in));
String line = r.readLine();

Intent intent = new Intent(RATE_CALCULATED_ACTION);
intent.putExtra(RATE_VALUE_KEY, 1.0/Double.parseDouble(line));
intent.putExtra(CURRENCY_FROM_KEY, fromCurrency);
intent.putExtra(CURRENCY_TO_KEY, toCurrency);

if (context != null)
context.sendBroadcast(intent);

return line;
}

} catch (NumberFormatException ex) {

} catch (NetworkOnMainThreadException ex) {

} catch (IOException ex) {
ex.printStackTrace();

}

return ("");
}


I create a most friendly method to get conversion rate from this class. This method is described below:

// this method starts a request to calculate rate. The result will be
// retrieved by a broadcastReceiver...
public void getConversionRate( String fromCurrency,
String toCurrency) {

execute(fromCurrency, toCurrency);

}

When I call execute, automatically the doInBackground is called.

MainActivity


We will see the MainActivity now. At this class it's the local where all happens, further because this class is responsable by display the main screen of application and  is in this local that broadcasts are received and treated.

I won't paste the code here, but you can see that in onCreated method are created the receivers. The start point to the process of send broadcast and receive broadcasts is the method refreshRates(). When the refreshRates is called, all currencies chosen by the user are sent to CurrencyAsync by the method getConversionRate. As each one of these requests are executed, a broadcast is received by the currencyAsyncTaskReceiver and the data is showed in the MainActivity.

It's best practice register the receivers on the onResume method and unregister on the onPause method if your application don't need of these receivers when the application isn't visible.

Preferences


The preferences screen has been using the PreferenceFramework from Android. First of all, it's very important know that the layout of preference screens aren't stored in res\layout folder. The layout of preference screens are stored in res\xml folder.

I used to build the preference screen of this application two different views, ListPreference and MultiSelectListPreference. Both work similarly, but ListPreference enable user select only one option and MultiSelectListPreference enable user select various options as it to want. The class that display the preferences is SettingsActitivity.

I hope have help you!




Regards!



quarta-feira, 30 de janeiro de 2013

Using Intents

Hello people,

After a long time I am writing a new post to you. In this post we will talk about the use of Intents.
According the book Professional Android 4 - Application Development "Intents are used as a message-passing mechanism that works both within your application and between applications", it means that you can create a application that uses actions from others applications. Actions will be a word mentioned many times here.

Using Intents you can start a Activity or a Service, to perform a action with (or on) a particular piece of data and broadcast that a event has occurred. Furthermore, you can take a lot of advantages from Intents to create a powerful application using even Android actions. I searched on the web good samples from use of Intents but I didn't success, so I created one exclusively to this post.

We will to use two applications during this post. At first we will to see like the intents works executing basics operations like start a new Activity and get results from it, after we will to see like these applications can interact between them.

I could use only one application to demonstrate like the interaction works, but I think is very interesting the experience of use two applications to talking between them.


ContactCentral

ContactCentral is the main application which we will work. Before we follow in this post, it is very important know that is necessary configure the permissions for the device resources that our application will be use. For this application we will send SMS, read the contacts and make calls. See the permissions declared in the AndroidManifest.xml:



 <!-- These permissions are used for this application -->
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />


When we try use anyone of this resources without declare the permissions a exception will occur.

Our application has a simple layout, the user can type a phone number and call this number or send a SMS, if the user do not remember the phone number, it can select one on the default Android contact list. To become easier to user clear the number, it can use the button clean.




Call

Make a call using the Android API is very easy. You need create a URI for the protocol "tel" and pass the phone number. After you will create a new Intent using the Android default action ACTION_CALL.  See the code below:


// creates a URI from phoneNumber...
String uri = "tel:" + editPhone.getText().toString();

// creates a Intent that will call phone number...
// This is a implicit intent...
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(uri));
startActivity(intent);

When the method startActivity is called, the default call screen is started. It is a implicit call to a Activity.


SMS

For start the actitivy that displays the SMS dialog, I had to create a new Activity called DialogSMS.


In this case we are calling this Activity explicitly.


// creates a URI from phoneNumber...
String phoneNumber = "tel:" + editPhone.getText().toString();
Bundle bundle = new Bundle();
bundle.putString(DialogSMS.KEY_PHONENUMBER, phoneNumber);

// creates a Intent that will call phone number...
// This is a explicit intent...
Intent intent = new Intent(getBaseContext(), DialogSMS.class);
intent.putExtra(DialogSMS.KEY_EXTRA, bundle);
startActivity(intent);


See that a Bundle is passed to Intent, this Bundle has the phone number that will be used within this Activity.
Build this example was very important and interesting because I could use a PendingIntent. A PendingIntent is a Intent that wait for a application or service to be used. In this case we will see that a PendingIntent is needed for receive the SMS send status. See the code below:


buttonSend = (Button) findViewById(R.id.dialogsms_send);
buttonSend.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

Bundle bundle = getIntent().getBundleExtra(KEY_EXTRA);
String phoneNumber = bundle.getString(KEY_PHONENUMBER);

PendingIntent sentPI = PendingIntent.getBroadcast(
getBaseContext(), 0, new Intent(ACTION_SENT), 0);


if(editMessage.getText().toString().length()==0)
{
Toast.makeText(
getApplicationContext(),
getResources()
.getString(
R.string.string_message_invalid_text),
Toast.LENGTH_SHORT).show();
return;
}

editMessage.setVisibility(View.GONE);
buttonCancel.setVisibility(View.GONE);
buttonSend.setVisibility(View.GONE);
setVisible(false);

SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, editMessage.getText()
.toString(), sentPI, null);


}
});

// when the SMS has been sent...
sendBroadcastReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(
getApplicationContext(),
getResources()
.getString(
R.string.string_message_has_been_sent),
Toast.LENGTH_SHORT).show();

break;
default:
Toast.makeText(
getApplicationContext(),
getResources()
.getString(
R.string.string_message_could_not_be_sent),
Toast.LENGTH_SHORT).show();

break;
}

finish();
}
};

registerReceiver(sendBroadcastReceiver,new IntentFilter(ACTION_SENT) );


In this code, the bundle passed for this Activity is used to retrieve the phone number. The PendingIntent is being declared and your Receiver is being built to receive the SMS send status and process this action.


Contact List

We will use the Android default contact list to select a contact to use. See that we are using a startActivityForResult for call this Intent. 

// this intent uses a action from the system to select
// contacts...
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
startActivityForResult(intent, PICK_CONTACT_CODE);

At this moment we will use the method onActivityResult from root Actitvity, for process the result from the contact selection. I could paste the code here, but I think it is very interesting you see the complete code in the source available for download. It is important to you seeing that the result of a contact pick is a URI that is used to search the contact on the list and display all phone numbers from each contact.


Calling the DialogSMS from other application

I built a application called CallDialogMessage that uses the popup dialog from ContactCentral. I used the startActivity to call the popup dialog, but we can the same using a broadcast, however, we should have created a receiver on ContactList.

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.contactcentral", "com.example.contactcentral.DialogSMS"));
String phoneNumber = "tel:123456789";
Bundle bundle = new Bundle();
bundle.putString("PHONENUMBER", phoneNumber);
intent.putExtra("EXTRA", bundle);
startActivity(intent);

It is not necessary worry us with the permissions on this application, because the permissions were declared on the main application.

I hope that you like of this post.

The code is avaliable here.

Thanks!