Android Programming for Android Geek
Monday, January 12, 2015
Wednesday, April 30, 2014
Install Android on Iphone is possible!!
If you've got an iPhone, are a little bored with iOS, and you're
interested in moonlighting with Google's Android operating system, you
can dual boot Android and iOS side-by-side on your iPhone in a few
relatively simple steps.
What You'll Need:
All you'll
need to get started is an iOS device; Right now, the iPhone 3G has the
best support, and that's what we're using in this guide.
Step One: Jailbreak Your iPhone
You've
got a number of jailbreaking options, including PwnageTool, Redsn0w,
and Blackra1n. Pick one that works on your platform, download it, and
walk through the jailbreak process. (I'm not going to detail the
jailbreak here since the latest jailbreaking methods often change a
little, but at this point, jailbreaking an iPhone is a relatively simple
process.)
Step Two: Install Bootlace in Cydia
In
order to do this, you'll need to launch Cydia from the homescreen, tap
on the Manage button, select Sources, then tap Edit, then Add. The
repository you'll need to add is repo.neonkoala.co.uk. Tap Add Source,
let Cydia work its magic, and then tap on your newly added repository
and install Bootlace.
Step Three: Run Bootlace and Patch the Kernel
Leave
Cydia, and launch Bootlace. If Bootlace isn't on your homescreen after
you leave Cydia, restart your iPhone and it should be there. Then just
launch Bootlace, and let it download and patch the kernel. When it's
done, tap on Reboot and wait for your phone to reboot.
Step Four: Install OpeniBoot
Now launch Bootlace again, tap the OpeniBoot button, and tap Install, then Continue. OpeniBoot will download and install.
Step Five: Install iDroid
Once
OpeniBoot is installed, tap the iDroid button, tap Install, OK, and
then wait. iDroid—which is essentially the Android OS customized for
your iPhone—will download and install. This will take a while, so be
patient, and if your battery is low, you may want to plug in your phone
before you start.
Step Six: Reboot and Play Around with Android
Now
you've installed Android on your iPhone. Time to play around with it.
Just tap on the QuickBoot button from inside Bootlace, tap the Android
icon (the one of the little Android proudly holding an Apple), and
confirm that you want to reboot into Android.
How Does It Work?
The first thing worth mentioning is that Android on iPhone isn't close to ready to use as your full-time mobile operating system. That doesn't mean it never will be, but at the moment, this is more something you'd want to do to fulfill your curiosity, wear as a geek badge, or just have a little fun and (maybe) support a really great project.
You can see how far they've come along with each phone on the iDroid status wiki.
As I mentioned above, the iPhone 3G is the best supported iOS device
(and currently only it and the 2G work with the method above, I
believe). The biggest issue right now with the 3G is power management
(PMU on the wiki), which isn't fully functional. Most importantly,
suspend isn't yet working, so your battery won't likely last long. It's
still come a long way from where it's been in the past, though, and
having followed this project excitedly for a while, the progress they've
made in recent weeks has been really impressive.
Regarding a
few nuts and bolts: Your iPhone's lock button acts as the Android back
button; the iPhone home button acts as the Android menu button; the
iPhone's volume down button acts as the Android home button; and the
iPhone's volume up button acts as... I'm not really sure what. To lock
the screen, press the iPhone's home and lock buttons at the same time.
To power off, hold the lock and home buttons for a couple of seconds
until the Power Off prompt appears. You can see a few other operating
quirks by watching the video above.
As you can
see in the video, performance isn't perfect (it's occasionally a little
laggy), but again, with time, that could change significantly. Either
way, the iDroid project—along with OpeniBoot and Bootlace—is something I
remain extremely excited about. As a long-time iPhone user and recent
Android switcher, the main thing that sets the two apart for me is the
iPhone hardware, which always feels head and shoulders above whatever
Android device I put my hands on. I know a lot of people (including
myself) who'd kill to dual boot an iPhone 4 with iOS and Android. (In
fact, if you really want to help out, you can donate to the iDroid
Project by clicking the Donate button on the top right of the iDroid Project's main page and maybe speed things along.)
Monday, April 28, 2014
Build Android from Lazaruz!!
Android Programming with Lazarus through Custom Drawn Interface
OK, so you've read that it's possible to write Android applications with Lazarus and Free Pascal. You go straight to the wiki,
follow the bunch of steps there and FAIL! And then you start grumbling
and doubting whether it's really possible or just a joke.
Listen up, dude. The Android support in FPC is still in development, and
a pure arm-android target has just been added a couple of months ago.
This target is available for those experienced enough with FPC
(bootstrapping the compiler, set options for building, etc.) and not
lazy to do the whole setup. Most problems come from those who don't read
and do the steps thoroughly, possibly skipping important part. So if
you're one of them, either change your behavior or wait until the
support is available in the stable release.
I will try to explain step by step setting up FPC trunk with arm-android
target support, followed by setting up Lazarus to support building
Android application. Note that it's all done on Linux (Kubuntu 13.04)
32-bit, but it should work for any supported host platforms.
First thing first, latest stable FPC
FPC is a bootstrapping compiler, and it's guaranteed that latest stable
version will be able to build trunk and next stable version. No
guarantee for older version or between revisions of trunk, and things
can be broken anytime on trunk. At this time of writing, latest stable
FPC is of version 2.6.2. So grab that one if yours is not.
Next, Android NDK
For arm-android target, FPC makes use of external assembler and linker provided by Android NDK.
Mine is still version r8e, but looking at the changelog version 9
should work just fine. Extract it anywhere you want, we will refer to
this location as {ndk.dir}. To be sure, right under {ndk.dir} there should be README.TXT and RELEASE.TXT.
Let's identify the tools we need:
- {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-as (assembler)
- {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ld (linker)
If you want, you can change the part after /toolchains/ in case you want
to use androideabi 4.6 or 4.7. Look at the corresponding directory you
have in your {ndk.dir}.
Open up your fpc.cfg file, by default it should contain the line:
-XP$FPCTARGET-
Ensure you do it correctly by verifying the output of ls -l `which arm-android-<toolname>` (*nix only). It looks like this on my system (real directory replaced with {ndk.dir}):
$ ls -l `which arm-android-as`
lrwxrwxrwx 1 root root 120 Mar 8 2013 /usr/bin/arm-android-as -> {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-as
$ ls -l `which arm-android-ld`
lrwxrwxrwx 1 root root 120 Mar 8 2013 /usr/bin/arm-android-ld -> {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ld
Try executing arm-android-as and arm-android-ld in terminal or command prompt to ensure it works.
Next, FPC trunk
Build FPC for arm-android target
make crossall OS_TARGET=android CPU_TARGET=arm CROSSOPT='-Cp<ARM Arch> -Cf<ARM VFP>'
<ARM Arch> defines the ARM architecture you want to compile for, my device is ARMv6, so I use -CpARMv6.
<ARM VFP> defines the Vector Floating Point unit you want to use for floating point calculation, for at least ARMv6, VFPv2 and VFPv3 are available. The default is to use soft-float, which is very slow as the calculation is performed by software. Since I seldom use floating point, soft-float is fine for me, so I don't pass any -Cf option.
If everything goes well, it's time to install. Execute the following (still in the same FPC trunk folder):
make crossinstall OS_TARGET=android CPU_TARGET=arm INSTALL_PREFIX=<directory of your choice>
Feel free to choose any directory you want, but ensure it fulfills the standard requirement (no space in the file path). I suggest installing to the same host FPC directory so you can easily share fpc.cfg. FPC directory structure is made such that it's possible to install cross compiler (and the respective units) in the same tree as the host compiler. The fpc driver can then be used to query which ppc[ross]XXX to call.
If everything goes well, test the compiler. Execute the following:
fpc -Parm -Tandroid
It should output something like:
Free Pascal Compiler version 2.7.1 [2013/09/21] for arm
Copyright (c) 1993-2013 by Florian Klaempfl and others
Fatal: No source file name in command line
Fatal: Compilation aborted
Error: /usr/bin/ppcrossarm returned an error exitcode
Next, Android SDK
Test AndroidLCL example, yay!
Go to your Lazarus installation directory (I will refer it as
{lazarus.dir} from now on) and open
examples/androidlcl/androidlcltest.lpi. Now open Project->Project
Options, ensure in Target Platform OS is set to android and CPU is set
to arm (or just pick the respective build mode). If upon FPC trunk
building you use -Cf option, specify the same option in Other. You might
need to also set it in Tools->Configure Build Lazarus dialog. Now
press the Run->Build menu. If you get:
Trying to use a unit which was compiled with a different FPU mode
Then you don't put the -Cf option correctly. Remember you will need to
put it for both your project (through Project Options dialog) and LCL
(and its dependencies, through Configure Build Lazarus).
If everything goes well, you will get android/libs/armeabi/liblclapp.so in the project folder.
Get Ant
Android SDK uses ant build tool for building apk, so you'll need to install it as well.
Build the APK
Go to android folder under androidlcl project folder, and open the build.xml. Inside, you will see 2 loadproperties and 1 property tags. These points to files you will need to edit to match your SDK installation. Mine is below:
<loadproperties srcFile="local.properties" />
<property file="ant.properties" />
<loadproperties srcFile="default.properties" />
local.properties contains the sdk.dir which you should fill with {sdk.dir} (actual value where you install it, of course).
default.properties contains the target android API level. The complete list can be seen here. Note that you have to install the respective SDK platform through Android SDK manager.
ant.properties contains key.store and key.alias which is required for
release version of your apk. For debug version, it's not required and
the apk builder utility will assign a debug key on its own.
If all set, execute:
ant debug
in android folder. The resulting .apk will be in android/bin folder named LCLExample-debug.apk. Install that and enjoy.
From this point forward, you can make use of androidlcl structure as a
template. General Java package structure and Android build system
knowledge will be required to change the package name.
Basic HTTP Client
Last year, the Android team recommended the use of java.net.HttpURLConnection instead of Apache HttpClient
for Gingerbread and up. Unfortunately, HttpURLConnection is a
lower-level API, so now everyone has to do their own URL encoding, set
MIME type application/x-www-form-urlencoded, read InputStream and
ErrorStream, wrap with try/catch, finally close streams, etc.
Rather than write all that code one-off for each request, I’ve created a basic HTTP client which lets you easily
To make an asynchronous request, you invoke the request methods (get,
post, etc.) with an additional argument, an AsyncCallback, which can be
easily implemented in an anonymous inner class as shown above. Here’s a
quick tour of the various clients you can use.
AsyncHttpClient adds an asynchronous API where each request method takes an extra callback argument. It is intended to be extended like AndroidHttpClient. Subclasses should provide a platform-specific wrapper for async requests. AndroidHttpClient provides an AsyncTask wrapper that AsyncHttpClient uses to make requests in the background.
BasicHttpClient and AndroidHttpClient both delegate the actual I/O to a BasicRequestHandler, which implements a simple request lifecycle (open, prepare, write, read, error). You can construct any of the clients with a custom RequestHandler. BasicRequestHandler is abstract so you can easily override only one method using an anonymous inner class. This is shown on the project home page. A common use for this may be to provide your own onError() method which determines whether a given error condition is recoverable for your application.
Enjoy!
Rather than write all that code one-off for each request, I’ve created a basic HTTP client which lets you easily
- make GET, POST, PUT, and DELETE requests
- make asynchronous requests with automatic retries and exponential backoff
- customize requests using a RequestHandler
- automatically wrap requests in an AsyncTask (Android-specific)
Basic usage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // Example code to login to App Engine dev server public void loginDev(String userEmail) { ParameterMap params = httpClient.newParams() .add( "continue" , "/" ) .add( "email" , userEmail) .add( "action" , "Log In" ); httpClient.addHeader( "someheader" , "value" ); httpClient.setConnectionTimeout( 2000 ); // 2s HttpResponse httpResponse = httpClient.post( "/_ah/login" , params); System.out.println(httpResponse.getBodyAsString()); } // Example code to log in to App Engine production app with an auth token // from Android's AccountManager public void loginProd(String authToken) { ParameterMap params = httpClient.newParams() .add( "auth" , authToken); HttpResponse httpResponse = httpClient.get( "/_ah/login" , params); } |
Make an asynchronous request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| httpClient.setMaxRetries( 5 ); ParameterMap params = httpClient.newParams() .add( "continue" , "/" ) .add( "email" , "test@example.com" ) .add( "action" , "Log In" ); httpClient.post( "/_ah/login" , params, new AsyncCallback() { @Override public void onComplete(HttpResponse httpResponse) { System.out.println(httpResponse.getBodyAsString()); } @Override public void onError(Exception e) { e.printStackTrace(); } }); |
BasicHttpClient
BasicHttpClient has no Android dependencies so it can be used on any platform which provides java.net.HttpURLConnection. It offers a synchronous interface only via get, post, put, and delete methods. Note that there are two post methods, one for posting form data (a ParameterMap) and one for uploading content of any type you specify. If you prefer, you can make a new HttpGetRequest and execute() it instead of using the get() method. In fact, all the request methods do this under the covers.AndroidHttpClient
AndroidHttpClient extends both AbstractHttpClient and AsyncHttpClient so it can used synchronously or asynchronously. Remember that you should not invoke the immediate (non-async) methods on the UI thread. Android will throw an exception if you do. Besides automatically wrapping requests in an AsyncTask via the async methods, AndroidHttpClient automatically includes the workaround for a major bug in HttpURLConnection in earlier versions of Android as discussed in the Android Developers blog post above.Cookie management
AbstractHttpClient (the base class for everything) registers a default java.net.CookieManager that is used by all HttpURLConnection requests in your VM (= app on Android). The default CookieManager acts just like a browser, remembering cookies it receives and sending them on subsequent requests. You shouldn’t need to set or read cookie headers manually at all. In fact, you can’t. When the CookieManager is in use, it consumes the cookie headers.Under the covers
AbstractHttpClient is the base client from which all the others flow. It implements a synchronous API and can be instantiated using an anonymous inner class if you just want the base functionality: new AbstractHttpClient() {}.AsyncHttpClient adds an asynchronous API where each request method takes an extra callback argument. It is intended to be extended like AndroidHttpClient. Subclasses should provide a platform-specific wrapper for async requests. AndroidHttpClient provides an AsyncTask wrapper that AsyncHttpClient uses to make requests in the background.
BasicHttpClient and AndroidHttpClient both delegate the actual I/O to a BasicRequestHandler, which implements a simple request lifecycle (open, prepare, write, read, error). You can construct any of the clients with a custom RequestHandler. BasicRequestHandler is abstract so you can easily override only one method using an anonymous inner class. This is shown on the project home page. A common use for this may be to provide your own onError() method which determines whether a given error condition is recoverable for your application.
Testing
There are no automated tests yet because I haven’t made the effort to simulate connections, timeouts, etc. I have done considerable manual testing, however, of the async capabilities with retries. The basic recipe is as follows:- Try an async request to an unreachable IP address (say, 10.0.0.1 or 192.168.1.1). This lets you observe connection timeouts and retries.
- Copy the SleepServlet in the test package to a Web project and add the servlet mapping in web.xml. Start the server and try an async request. This lets you observe read timeouts and retries.
- Try an async request to a functioning URL and observe success.
Summary
The code is copiously commented with hopefully non-trivial observations about function and intended use. Planned enhancements include a MappingJsonClient which can take POJO arguments instead of raw bytes or Strings. Spring for Android already has a nice RestTemplate, but like Apache HttpClient, is fairly heavyweight on account of its configurability.Enjoy!
Android SimpleHTMLParser
Android : Simple HTML parsing & image downloader using AsyncTask
A barebone html parser and a simple image downloader for a certain comic. This one may please your girlfriend or wife. I'll show a simple DefaultHttpClient and ResponseHandle in conjunction with a AsyncTask class.(Although with almost no error checking) The comic we want is Love Is, i've stripped it so it's just a ImageView for the image, a button for Previous/Next and a simple TextView for the date.
Lets start with the simple helper class that will connect to the homepage, parse the html and download the image.
Update, GoComics.com have removed their Love Is... comic strip. Updated it with another page.
(note only updated LoveIsParser.java, they use strange dates for their pictures, reused ones ? So need to store url to previous and next picture before closing the AsyncTask... just did a quick hack to get it working again.)
src/LoveIsParser.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LoveIsParser {
final String loveIsUrl = "http://loveiscomix.com/";
private String urlImage;
private Bitmap loveIsBitmap;
private Pattern patternForImage = Pattern.compile("static/loveisbnk/.........gif");
public LoveIsParser()
{ }
public Bitmap getLoveIsBitmap()
{
return loveIsBitmap;
}
public boolean downloadImage(Calendar c)
{
//String urlExtension = c.get(Calendar.YEAR) + "/" + padString(c.get(Calendar.MONTH)+1) + "/" + padString(c.get(Calendar.DAY_OF_MONTH));
//Log.d("LoveIS Url:", loveIsUrl + urlExtension);
DefaultHttpClient httpClient = new DefaultHttpClient();
BasicResponseHandler responseHandler = new BasicResponseHandler();
HttpGet request = new HttpGet(loveIsUrl);
try
{
String htmlBody = httpClient.execute(request, responseHandler);
Matcher m = patternForImage.matcher(htmlBody);
if(m.find())
{
urlImage = m.group();
urlImage = loveIsUrl + urlImage;
Log.d("Image Url:", urlImage);
request = new HttpGet(urlImage);
HttpResponse response = httpClient.execute(request);
InputStream in = response.getEntity().getContent();
BufferedInputStream bis = new BufferedInputStream(in, 8192);
loveIsBitmap = BitmapFactory.decodeStream(bis);
bis.close();
in.close();
return true;
}
}
catch (Exception e)
{
Log.d("Exception", e.toString());
}
return false;
}
public String padString(int number)
{
return String.format("%02d", number);
}
}
Most is self explanatory, downloadImage function takes a Calendar, parses the date and completes the url.
Adding 1 to the month as it's zero-based and using padString to pad with a 0 if it's singledigit.
Lets move on to the layout.
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">
<ImageView android:id="@+id/ivLove"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
<TextView android:id="@+id/tvDate"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/btnPrevious"
android:text="Previous"/>
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/btnNext"
android:text="Next"/>
</LinearLayout>
And lastly our launcher activity.
src/MainActivity.java
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Calendar;
public class MainActivity extends FragmentActivity {
Calendar c;
TextView tvDate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loveis);
c = Calendar.getInstance();
ImageView imageView = (ImageView) findViewById(R.id.ivLove);
tvDate = (TextView) findViewById(R.id.tvDate);
tvDate.setText(c.getTime().toLocaleString());
Button btnPrevious = (Button) findViewById(R.id.btnPrevious);
Button btnNext = (Button) findViewById(R.id.btnNext);
if(isOnline())
new GetAndSetImage().execute(c);
else
Toast.makeText(this, "No Internet connection found.", Toast.LENGTH_LONG).show();
btnPrevious.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
c.add(Calendar.DATE, -1);
tvDate.setText(c.getTime().toLocaleString());
new GetAndSetImage().execute(c);
}
});
btnNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
c.add(Calendar.DATE, 1);
tvDate.setText(c.getTime().toLocaleString());
new GetAndSetImage().execute(c);
}
});
}
private class GetAndSetImage extends AsyncTask<Calendar, Void, Bitmap>
{
ProgressDialog pd;
@Override
protected Bitmap doInBackground(Calendar... c) {
LoveIsParser parser = new LoveIsParser();
if(parser.downloadImage(c[0]))
return parser.getLoveIsBitmap();
else
{ // We just return a drawable if there's an error in the download.
return BitmapFactory.decodeResource(getResources(), R.drawable.icon);
}
}
@Override
protected void onPreExecute()
{
pd = new ProgressDialog(MainActivity.this);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("Downloading image...");
pd.show();
}
@Override
protected void onPostExecute(Bitmap bm)
{
pd.dismiss();
ImageView iv = (ImageView) findViewById(R.id.ivLove);
iv.setImageBitmap(bm);
}
}
public boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
}
Buttons decrease and increase the date when clicked and download the image based on the current date using a simple AsyncTask that display a 'Progress Dialog' while it's downloading.
Now just flash it up a bit (hearts and red layout ^^) and install on your girlfriends phone for some extra romance, or implement sharing so you can easily send the picture as an MMS whenever you want.
A barebone html parser and a simple image downloader for a certain comic. This one may please your girlfriend or wife. I'll show a simple DefaultHttpClient and ResponseHandle in conjunction with a AsyncTask class.(Although with almost no error checking) The comic we want is Love Is, i've stripped it so it's just a ImageView for the image, a button for Previous/Next and a simple TextView for the date.
Lets start with the simple helper class that will connect to the homepage, parse the html and download the image.
Update, GoComics.com have removed their Love Is... comic strip. Updated it with another page.
(note only updated LoveIsParser.java, they use strange dates for their pictures, reused ones ? So need to store url to previous and next picture before closing the AsyncTask... just did a quick hack to get it working again.)
src/LoveIsParser.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LoveIsParser {
final String loveIsUrl = "http://loveiscomix.com/";
private String urlImage;
private Bitmap loveIsBitmap;
private Pattern patternForImage = Pattern.compile("static/loveisbnk/.........gif");
public LoveIsParser()
{ }
public Bitmap getLoveIsBitmap()
{
return loveIsBitmap;
}
public boolean downloadImage(Calendar c)
{
//String urlExtension = c.get(Calendar.YEAR) + "/" + padString(c.get(Calendar.MONTH)+1) + "/" + padString(c.get(Calendar.DAY_OF_MONTH));
//Log.d("LoveIS Url:", loveIsUrl + urlExtension);
DefaultHttpClient httpClient = new DefaultHttpClient();
BasicResponseHandler responseHandler = new BasicResponseHandler();
HttpGet request = new HttpGet(loveIsUrl);
try
{
String htmlBody = httpClient.execute(request, responseHandler);
Matcher m = patternForImage.matcher(htmlBody);
if(m.find())
{
urlImage = m.group();
urlImage = loveIsUrl + urlImage;
Log.d("Image Url:", urlImage);
request = new HttpGet(urlImage);
HttpResponse response = httpClient.execute(request);
InputStream in = response.getEntity().getContent();
BufferedInputStream bis = new BufferedInputStream(in, 8192);
loveIsBitmap = BitmapFactory.decodeStream(bis);
bis.close();
in.close();
return true;
}
}
catch (Exception e)
{
Log.d("Exception", e.toString());
}
return false;
}
public String padString(int number)
{
return String.format("%02d", number);
}
}
Most is self explanatory, downloadImage function takes a Calendar, parses the date and completes the url.
Adding 1 to the month as it's zero-based and using padString to pad with a 0 if it's singledigit.
Lets move on to the layout.
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">
<ImageView android:id="@+id/ivLove"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
<TextView android:id="@+id/tvDate"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/btnPrevious"
android:text="Previous"/>
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/btnNext"
android:text="Next"/>
</LinearLayout>
And lastly our launcher activity.
src/MainActivity.java
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Calendar;
public class MainActivity extends FragmentActivity {
Calendar c;
TextView tvDate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loveis);
c = Calendar.getInstance();
ImageView imageView = (ImageView) findViewById(R.id.ivLove);
tvDate = (TextView) findViewById(R.id.tvDate);
tvDate.setText(c.getTime().toLocaleString());
Button btnPrevious = (Button) findViewById(R.id.btnPrevious);
Button btnNext = (Button) findViewById(R.id.btnNext);
if(isOnline())
new GetAndSetImage().execute(c);
else
Toast.makeText(this, "No Internet connection found.", Toast.LENGTH_LONG).show();
btnPrevious.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
c.add(Calendar.DATE, -1);
tvDate.setText(c.getTime().toLocaleString());
new GetAndSetImage().execute(c);
}
});
btnNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
c.add(Calendar.DATE, 1);
tvDate.setText(c.getTime().toLocaleString());
new GetAndSetImage().execute(c);
}
});
}
private class GetAndSetImage extends AsyncTask<Calendar, Void, Bitmap>
{
ProgressDialog pd;
@Override
protected Bitmap doInBackground(Calendar... c) {
LoveIsParser parser = new LoveIsParser();
if(parser.downloadImage(c[0]))
return parser.getLoveIsBitmap();
else
{ // We just return a drawable if there's an error in the download.
return BitmapFactory.decodeResource(getResources(), R.drawable.icon);
}
}
@Override
protected void onPreExecute()
{
pd = new ProgressDialog(MainActivity.this);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("Downloading image...");
pd.show();
}
@Override
protected void onPostExecute(Bitmap bm)
{
pd.dismiss();
ImageView iv = (ImageView) findViewById(R.id.ivLove);
iv.setImageBitmap(bm);
}
}
public boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
}
Buttons decrease and increase the date when clicked and download the image based on the current date using a simple AsyncTask that display a 'Progress Dialog' while it's downloading.
Now just flash it up a bit (hearts and red layout ^^) and install on your girlfriends phone for some extra romance, or implement sharing so you can easily send the picture as an MMS whenever you want.
Wednesday, November 14, 2012
Android Programming Hello World
1. What is Android?
Android
is an operating system based on the Linux kernel. The
project
responsible for developing the Android system is called the
Android Open Source Project
(AOSP)
and is primarily lead
by Google.
The Android system supports background processing, provides a rich user interface library, supports 2-D and 3-D graphics using the OpenGL-ES (short OpenGL) standard and grants access to the file system as well as an embedded SQLite database.
An Android application typically consists of different visual and non visual components and can reuse components of other applications.
The Android system supports background processing, provides a rich user interface library, supports 2-D and 3-D graphics using the OpenGL-ES (short OpenGL) standard and grants access to the file system as well as an embedded SQLite database.
An Android application typically consists of different visual and non visual components and can reuse components of other applications.
In Android the reuse of other application components is a concept
known
as
task. An application can access other Android components to achieve a
task.
For example, from a component of your application you can
trigger
another component in the Android system, which manages photos,
even
if
this component is not part of your application. In this
component you
select a photo and return to your application to use the
selected
photo.
Such a flow of events is depicted in the following graphic.
Such a flow of events is depicted in the following graphic.
The Android system is a full software stack, which is typically
divided into the four areas as depicted in the following graphic.
The levels can be described as:
The Linux kernel, the libraries and the runtime are encapsulated by the application framework. The Android application developer typically works with the two layers on top to create new Android applications.
The levels can be described as:
-
Applications - The Android Open Source Project contains
several default application, like the Browser, Camera, Gallery,
Music, Phone and more.
-
Application framework - An API which allows high-level
interactions with the Android system from Android applications.
-
Libraries and runtime - The libraries for many common
functions
(e.g.: graphic rendering, data storage, web browsing,
etc.) of the
Application Framework and the Dalvik runtime, as well
as the core
Java libraries for running Android applications.
-
Linux kernel - Communication layer for the underlying
hardware.
The Linux kernel, the libraries and the runtime are encapsulated by the application framework. The Android application developer typically works with the two layers on top to create new Android applications.
Google offers the
Google Play
service, a marketplace in which programmers can
offer their Android
applications to
Android users. Customers use the
Google Play
application
which allows them to buy and install
applications from the
Google
Play service.
Google Play also offers an update service. If a programmer uploads a new version of his application to Google Play, this service notifies existing users that an update is available and allows them to install the update.
Google Play provides access to services and libraries for Android application programmers, too. For example, it provides a service to use and display Google Maps and another to synchronize the application state between different Android installations. Providing these services via Google Play has the advantage that they are available for older Android releases and can be updated by Google without the need for an update of the Android release on the phone.
Google Play also offers an update service. If a programmer uploads a new version of his application to Google Play, this service notifies existing users that an update is available and allows them to install the update.
Google Play provides access to services and libraries for Android application programmers, too. For example, it provides a service to use and display Google Maps and another to synchronize the application state between different Android installations. Providing these services via Google Play has the advantage that they are available for older Android releases and can be updated by Google without the need for an update of the Android release on the phone.
The
Android Software Development Kit
(Android SDK) contains the necessary tools to create, compile
and
package
Android applications. Most of these tools are command line
based. The
primary way to develop
Android applications is based on the
Java
programming
language.
The Android SDK contains the
Android debug bridge
(adb), which is a tool that allows you to connect to a virtual or
real
Android
device, for the purpose of managing the device or
debugging your
application.
Google provides two integrated development environments (IDEs)
to
develop new
applications.
The Android Developer Tools (ADT) are based on the Eclipse IDE. ADT is a set of components (plug-ins), which extend the Eclipse IDE with Android development capabilities.
Google also supports an IDE called Android Studio for creating Android applications. This IDE is based on the IntelliJ IDE.
Both IDEs contain all required functionality to create, compile, debug and deploy Android applications. They also allow the developer to create and start virtual Android devices for testing.
Both tools provide specialized editors for Android specific files. Most of Android's configuration files are based on XML. In this case these editors allow you to switch between the XML representation of the file and a structured user interface for entering the data.
The Android Developer Tools (ADT) are based on the Eclipse IDE. ADT is a set of components (plug-ins), which extend the Eclipse IDE with Android development capabilities.
Google also supports an IDE called Android Studio for creating Android applications. This IDE is based on the IntelliJ IDE.
Both IDEs contain all required functionality to create, compile, debug and deploy Android applications. They also allow the developer to create and start virtual Android devices for testing.
Both tools provide specialized editors for Android specific files. Most of Android's configuration files are based on XML. In this case these editors allow you to switch between the XML representation of the file and a structured user interface for entering the data.
The Android system uses a special virtual machine, i.e., the
Dalvik Virtual Machine
(Dalvik)
to run Java based applications. Dalvik uses a
custom
bytecode
format
which is different from Java bytecode.
Therefore you cannot run Java class files on Android directly; they need to be converted into the Dalvik bytecode format.
Therefore you cannot run Java class files on Android directly; they need to be converted into the Dalvik bytecode format.
Similar to the JVM, Dalvik optimizes the application at runtime.
This is known as
Just In Time
(JIT) compilation. If
a part of the application is
called
frequently,
Dalvik will optimize
this part of the code and
compile it
into machine
code which executes
much faster.
With Android 4.4, Google introduced the
Android RunTime
(ART) as optional runtime for Android 4.4. It is expected that
versions
after 4.4 will use ART as default runtime.
ART uses Ahead Of Time compilation. During the deployment process of an application on an Android device, the application code is translated into machine code. This results in approx. 30% larger compile code, but allows faster execution from the beginning of the application.
ART uses Ahead Of Time compilation. During the deployment process of an application on an Android device, the application code is translated into machine code. This results in approx. 30% larger compile code, but allows faster execution from the beginning of the application.
Android applications are primarily written in the Java
programming
language.
During development the developer creates the Android specific configuration files and writes the application logic in the Java programming language.
The ADT or the Android Studio tools convert these application files, transparently to the user, into an Android application. When developers trigger the deployment in their IDE, the whole Android application is compiled, packaged, deployed and started.
During development the developer creates the Android specific configuration files and writes the application logic in the Java programming language.
The ADT or the Android Studio tools convert these application files, transparently to the user, into an Android application. When developers trigger the deployment in their IDE, the whole Android application is compiled, packaged, deployed and started.
The Java source files are converted to Java
class files by
the
Java
compiler.
The Android SDK contains a tool called dx which converts Java class files into a
For example, if the same
These
The
The resulting
The Android SDK contains a tool called dx which converts Java class files into a
.dex
(Dalvik Executable)
file. All class files of the application are
placed in this
.dex
file. During this conversion process
redundant
information in the class
files are optimized in the
.dex
file.
For example, if the same
String
is found in different class
files,
the
.dex
file
contains only one reference of this
String
.
These
.dex
files are therefore
much smaller in size
than the
corresponding
class
files.
The
.dex
file and the resources of an Android project, e.g., the
images and
XML
files, are packed into an
.apk
(Android Package)
file. The program
aapt
(Android Asset Packaging Tool) performs this step.
The resulting
.apk
file contains all necessary data to run the
Android application and
can be deployed to an Android device via the
adb
tool.
The Android system installs every Android application with a
unique user and group ID. Each
application file is private to this
generated user, e.g., other
applications cannot access these files. In
addition each Android application is started in its own
process.
Therefore, by means of the underlying Linux kernel, every Android application is isolated from other running applications.
If data should be shared, the application must do this explicitly via an Android component which handles the sharing of the data, e.g., via a service or a content provider.
Therefore, by means of the underlying Linux kernel, every Android application is isolated from other running applications.
If data should be shared, the application must do this explicitly via an Android component which handles the sharing of the data, e.g., via a service or a content provider.
Android contains a permission system and predefines
permissions
for certain tasks. Every application can request
required
permissions
and also define new permissions. For example, an application may
declare
that it
requires access to the Internet.
Permissions have different levels. Some permissions are automatically granted by the Android system, some are automatically rejected. In most cases the requested permissions are presented to the user before installing the application. The user needs to decide if these permissions shall be given to the application.
If the user denies a required permission, the related application cannot be installed. The check of the permission is only performed during installation, permissions cannot be denied or granted after the installation.
An Android application declares the required permissions in its
Permissions have different levels. Some permissions are automatically granted by the Android system, some are automatically rejected. In most cases the requested permissions are presented to the user before installing the application. The user needs to decide if these permissions shall be given to the application.
If the user denies a required permission, the related application cannot be installed. The check of the permission is only performed during installation, permissions cannot be denied or granted after the installation.
An Android application declares the required permissions in its
AndroidManifest.xml
configuration file. It can also define additional permissions which
it can use to restrict access to certain components.
Note
Not all users pay attention to the required permissions during installation. But some users do and they write negative reviews on Google Play if they believe the application is too invasive.
Google provides a packaged and configured
Android
development
environment based on the Eclipse IDE called
Android Developer Tools.
Under the
following URL you find
an
archive
file which includes
all
required tools
for Android
development:
Getting the Android SDK.
Extract the zip file and start the Android Developer Tools (Eclipse)
which are located in the
eclipse
folder.
You can do this by double-clicking on the
eclipse
native launcher (e.g.,
eclipse.exe
under Windows).
See
???
for a description on how to update your existing Eclipse IDE to perform
Android development.
The simplest way to start Android development with Eclipse is to
download a complete and pre-configured bundle
as described in
Section 4.1.1, “Download packaged Android Developer Tools”. It is also possible to update an existing Eclipse installation.
Please
see
Android installation
for a detailed description
The Android SDK contains an Android device emulator. This
emulator
can
be
used to run an
Android Virtual Device
(AVD), which
emulates a real Android phone. Such an emulator is
displayed in the following screenshot.
AVDs allow you to test your Android applications on different Android versions and configurations without access to the real hardware.
During the creation of your AVD you define the configuration for the virtual device. This includes, for example, the resolution, the Android API version and the density of your display.
You can define multiple AVDs with different configurations and start them in parallel. This allows you to test different device configurations at once.
AVDs allow you to test your Android applications on different Android versions and configurations without access to the real hardware.
During the creation of your AVD you define the configuration for the virtual device. This includes, for example, the resolution, the Android API version and the density of your display.
You can define multiple AVDs with different configurations and start them in parallel. This allows you to test different device configurations at once.
The following table lists useful shortcuts for working with an AVD.
Table 1. Android device emulator shortcuts
Shortcut | Description |
---|---|
Alt+Enter | Maximizes the emulator. |
Ctrl+F11 | Changes the orientation of the emulator from landscape to portrait and vice versa. |
F8 | Turns the network on and off. |
During the creation of an AVD you decide if
you want to create an
Android
device or a
Google device.
An AVD created for Android contains the programs from the Android Open Source Project. An AVD created for the Google API's contains additional Google specific code.
AVDs created for the Google API allow you to test applications which use Google Play services, e.g., the new Google maps API or the new location services.
An AVD created for Android contains the programs from the Android Open Source Project. An AVD created for the Google API's contains additional Google specific code.
AVDs created for the Google API allow you to test applications which use Google Play services, e.g., the new Google maps API or the new location services.
During the creation of an emulator you can choose if you either want
Snapshot
or
Use Host GPU
enabled.
If you select the
Snapshot
option, the second time you start the device it is started very fast,
because the AVD stores its state if you close it. If you select
Use Host GPU
the AVD uses the graphics card of your host computer directly which
makes the
rendering on the emulated device much faster.
Note
The dialog implies that you can select both options, but if you do, you get an error message that these options can not be selected together.
It is possible to run an AVD with an image based on the ARM CPU
architecture or based on the Intel CPI architecture.
An Android virtual device which uses the Intel system image is much faster in execution on Intel / AMD hardware compared to the ARM based system image. This is because the emulator does not need to translate the ARM CPU instructions to the Intel / AMD CPU on your computer.
An Android virtual device which uses the Intel system image is much faster in execution on Intel / AMD hardware compared to the ARM based system image. This is because the emulator does not need to translate the ARM CPU instructions to the Intel / AMD CPU on your computer.
Subscribe to:
Posts (Atom)