Thứ Năm, 7 tháng 6, 2012

Android: Problem with Conversion to Dalvik format

While working with Android on Eclipse through ADT, deploying an Android app, this wolf has met another error message like:

"Conversion to Dalvik format failed: Unable to execute dex: Java heap space"


The wolf has sniffing on the internet and found good solution for it.

The reason: Eclipse didn't allocate memory enough for running in this case.
The default memory setting on Eclipse (Indiago) was "-Xms40m -Xmx384m"
 
 Solution:
  1. Change these value to another bigger (like "-Xms256m -Xmx1024m") in the "eclipse.ini" file at the root of Eclipse's folder.
  2. Restart the Eclipse, you should terminate the "adb.exe" process in Tasks Manager. But, it doesn't matter.
  3. (HAVE TO) Clean up project and Build it again.

Then, it continue enjoying the bone.
(Refer edfrom Internet and StackOverflow)

Thứ Tư, 7 tháng 9, 2011

Android: Implementing Word Prediction and Completion on Android IME



Implementing Word Prediction and Completion on Android IME

This thread is giving an lightly explanation of Android Input Method Framework (IMF), life-cycle of Input Method (IME) and the word prediction/completion in composing.

I. Architecture

There are three primary parties involved in the IMF architecture:

  • The Input method manager as expressed by this class (InputMethodManager) is the central point of the system that manages interaction between all other parts. It is expressed as the client-side API here which exists in each application context and communicates with a global system service that manages the interaction across all processes.
  • An Input method (IME) service implements a particular interaction model allowing the user to generate text. The system binds to the current input method that is use, causing it to be created and run, and tells it when to hide and show its UI. Only one IME is running at a time.
  • Multiple client applications arbitrate with the input method manager for input focus and control over the state of the IME. Only one such client is ever active (working with the IME) at a time.

II. InputMethod (IME) Overview
  • An input method (IME) is implemented as a Service, typically deriving from InputMethodService? . It must provide the core InputMethod? interface, though this is normally handled by InputMethodService? and implementors will only need to deal with the higher-level API there.
  • The InputMethodService? provides a basic framework for standard UI elements (input view, candidates view, and running in fullscreen mode), but it is up to a particular implementor to decide how to use them. For example, one input method could implement an input area with a keyboard, another could allow the user to draw text, while a third could have no input area (and thus not be visible to the user) but instead listen to audio and perform text to speech conversion.
  • The normal Service lifecycle methods, the InputMethodService? class introduces some new specific callbacks that most subclasses will want to make use of:
    • onInitializeInterface() for user-interface initialization, in particular to deal with configuration changes while the service is running.
    • onBindInput() to find out about switching to a new client.
    • onStartInput(EditorInfo? , boolean) to deal with an input session starting with the client.
    • onCreateInputView(), onCreateCandidatesView(), and onCreateExtractTextView() for non-demand generation of the UI.
    • onStartInputView(EditorInfo? , boolean) to deal with input starting within the input area of the IME.
To create an input method (IME) for entering text into text fields and other Views, you need to extend android.inputmethodservice.InputMethodService. This API provides much of the basic implementation for an input method, in terms of managing the state and visibility of the input method and communicating with the currently visible activity. The typical life-cycle of an InputMethodService looks like this:

CandidateView is the place where potential word corrections or completions are presented to the user for selection. Again, this may or may not be relevant to your input method and you can return null from calls to InputMethodService.onCreateCandidatesView(), which is the default behavior. By creating a layout for candidates and implement onCreateCandidatesView() method, developer can show the word prediction/completions when user is typing on the virtual keyboard.

III. Implementation

The DFD below in basically show the most popular implemented in Android's IME applications (Android's IME, Latin IME, ZhuYin IME ...)
plz click to enlarge

And here is the architecture for a new prediction/completion method on IME:


(not yet complete...)

Thứ Ba, 10 tháng 5, 2011

Android: Problem with "Unparsed aapt error(s)! Check the console for output."

Sometimes, on Eclipse ADT, you can get into this problem:
Unparsed aapt error(s)! Check the console for output. line N
The result for this error was: there has some error(or conflict) in a *.xml in the project
Solution:
- Fix/remove the xml that lead to the error.
- Clean up project and rebuild.

Just research and note!!

Thứ Hai, 27 tháng 12, 2010

Android: Problem with "Debug Certificate expired on.."

This note is created for anybody who have the same issue like me when built an Android project by Eclipse and got "Error generating final archive: Debug certificate expired on !". It occurs to me when i tried to open and build a very old Android project. The reason for it happened is:
Android required the applications to be signed even in the debug mode. So it uses a keystore file called debug.keystore to provide keys for signing applications in debug mode. This key store file has a validity period by default 365 days from its creation date.
(From Android-pro)
And there have 2 ways to resolve this issue:
A. Navigate to the ".android" folder in your home directory
~/.android” (Linux,Mac OS) or
"C:\Documents and Settings\[User Name]\.android
" in windows XP or
"C:\Users\[User Name]\.android"
in windows Vista or Windows 7,
then delete debug.keystore file. Then go to eclipse clean the project, this will create a new debug.keystore file with default validity period 365 days.
."
Or
Create a new default.keystore file with custom validity period (say 1000 days).
  1. Navigate to the ".android" folder.
  2. Delete the old default.keystore file.
  3. We will use JDK Keytool.exe to generate the new key file. It is found in
  4. Run the following command in the "cmd" (or terminate):
    keytool -genkey -keypass android -keystore debug.keystore -alias androiddebugkey -storepass android -validity 1000 -dname “CN=Android Debug,O=Android,C=US”
  5. This will generate a new default.keystore file with validity period 1000 days.
  6. Copy the generated file to the ".android" folder, go to eclipse and clean projects and it should work.
Good luck,

Thứ Hai, 15 tháng 11, 2010

Android: Problem with "DalVM" when build project

This note is created for anybody who have the same issue like me when built an Android project and got "Conversion to dalvik format failed with error 1". It occurs to me when i tried to open and build a very old Android project. The reason for it happened is:

DX tool can not convert all java classes to dex format then this error occurs. In my case when i was getting error because there are some class which are using Java standard edition references and can not converted to dex. Generally it will convert all J2Me lib to dex format.

Second scenario is that when you are changing target platform or work space then there might be some inconsistency in build and it was fixed by just cleaning and rebuilding workspace.

(From Bimbim.in)

As the suggestion from Bimbim.in, they said:
"please clean your project and rebuild it when you are getting this exception."
but, one more thing had to be done before:
Right click on the project, move the cursor to Android Tools and choose "Fix Project Properties"

Good luck,

Thứ Hai, 25 tháng 10, 2010

Android: SDK - Development Tools 01

DX

The dx tool lets you generate Android bytecode from .class files. The tool converts target files and/or directories to Dalvik executable format (.dex) files, so that they can run in the Android environment. It can also dump the class files in a human-readable format and run a target unit test. You can get the usage and options for this tool by using dx --help.

This tool was placed in : %sdk%\platforms\%androidplatform%\tools\

AAPT

aapt stands for Android Asset Packaging Tool and is included in the tools/ directory of the SDK. This tool allows you to view, create, and update Zip-compatible archives (zip, jar, apk). It can also compile resources into binary assets.

Though you probably won't often use aapt directly, build scripts and IDE plugins can utilize this tool to package the apk file that constitutes an Android application.

This tool was placed in : %sdk%\platforms\%androidplatform%\tools\

AIDL

AIDL (Android Interface Definition Language) is an IDL language used to generate code that enables two processes on an Android-powered device to talk using interprocess communication (IPC). If you have code in one process (for example, in an Activity) that needs to call methods on an object in another process (for example, a Service), you would use AIDL to generate code to marshall the parameters.

The AIDL IPC mechanism is interface-based, similar to COM or Corba, but lighter weight. It uses a proxy class to pass values between the client and the implementation.
(In detail at Android - aidl)

(Refer from Development Android)

Thứ Hai, 28 tháng 6, 2010

Android: How to upgrade your Nexus One from Android 2.1 to 2.2?

To manually install Android 2.2 on the Nexus One, perform the following steps:

  1. Download the official Android 2.2 firmware for the Nexus One.
  2. Copy the file to your microSD card and name it update.zip (newb warning: not update.zip.zip)
  3. Power off your phone.
  4. Hold down the VOLUME DOWN button and power it back on.
  5. The phone will now search for files like PB00IMG.zip, etc. This is normal. Scroll down to recovery and press the POWER button.
  6. When you see the “/!\” symbol, press the POWER button and the Volume Up button at the same time. You should be presented with a menu and one of the options should be “Apply sdcard:update.zip”.
  7. Use the trackball to navigate to “apply sdcard:update.zip” and select it.
  8. When you see “Install from sdcard complete”, select “reboot system now”.

Enjoy and once you’ve had a chance to play for awhile let us know what you think.

The resources:
- Upgrade from Android 2.1 (ERE27) to FRF50.
- Upgrade from FRF50 to FRF83.
- Upgrade from FRF72 to FRF83.
- Upgrade from ERD79 to ERE27. (~16MB),
22607-ERD79-update-nexusone-stock-signed-boot-img. (~2MB)
- Update for ERE27. (~65MB)

(Referred from: AndroidAndMe, Links from the Net)

Thứ Hai, 19 tháng 4, 2010

Avoiding Memory Leaks

From: http://developer.android.com/resources/articles/avoiding-memory-leaks.html

Android applications are, at least on the T-Mobile G1, limited to 16 MB of heap. It's both a lot of memory for a phone and yet very little for what some developers want to achieve. Even if you do not plan on using all of this memory, you should use as little as possible to let other applications run without getting them killed. The more applications Android can keep in memory, the faster it will be for the user to switch between his apps. As part of my job, I ran into memory leaks issues in Android applications and they are most of the time due to the same mistake: keeping a long-lived reference to a Context.

On Android, a Context is used for many operations but mostly to load and access resources. This is why all the widgets receive a Context parameter in their constructor. In a regular Android application, you usually have two kinds of Context, Activity and Application. It's usually the first one that the developer passes to classes and methods that need a Context:

@Override
protected void onCreate(Bundle state) {
super.onCreate(state);

TextView label = new TextView(this);
label.setText("Leaks are bad");

setContentView(label);
}

This means that views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources. Therefore, if you leak the Context ("leak" meaning you keep a reference to it thus preventing the GC from collecting it), you leak a lot of memory. Leaking an entire activity can be really easy if you're not careful.

When the screen orientation changes the system will, by default, destroy the current activity and create a new one while preserving its state. In doing so, Android will reload the application's UI from the resources. Now imagine you wrote an application with a large bitmap that you don't want to load on every rotation. The easiest way to keep it around and not having to reload it on every rotation is to keep in a static field:

private static Drawable sBackground;

@Override
protected void onCreate(Bundle state) {
super.onCreate(state);

TextView label = new TextView(this);
label.setText("Leaks are bad");

if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);

setContentView(label);
}

This code is very fast and also very wrong; it leaks the first activity created upon the first screen orientation change. When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context) which in turns has references to pretty much anything (depending on your code.)

This example is one of the simplest cases of leaking the Context and you can see how we worked around it in the Home screen's source code (look for the unbindDrawables() method) by setting the stored drawables' callbacks to null when the activity is destroyed. Interestingly enough, there are cases where you can create a chain of leaked contexts, and they are bad. They make you run out of memory rather quickly.

There are two easy ways to avoid context-related memory leaks. The most obvious one is to avoid escaping the context outside of its own scope. The example above showed the case of a static reference but inner classes and their implicit reference to the outer class can be equally dangerous. The second solution is to use the Application context. This context will live as long as your application is alive and does not depend on the activities life cycle. If you plan on keeping long-lived objects that need a context, remember the application object. You can obtain it easily by calling Context.getApplicationContext() or Activity.getApplication().

In summary, to avoid context-related memory leaks, remember the following:

* Do not keep long-lived references to a context-activity (a reference to an activity s

có liên quan tới: Avoiding Memory Leaks | Android Developers (xem trên Google Sidewiki)

Thứ Năm, 8 tháng 4, 2010

Android - Killing Processes

http://developer.android.com/reference/android/os/Process.html#killProcess%28int%29

Due to kernel restriction, Process.killProcess(processID) is not allowed to kill processes that they did not in the application package/system-default application like: Calculator, BrowserActivity, ...

Using:
>adb -[option d/e] shell top
to show updated running processes.

có liên quan tới: Process | Android Developers (xem trên Google Sidewiki)

Thứ Sáu, 22 tháng 1, 2010

Android: Emulator

Using "-cpu-delay <delayinMs>" to slow down your emulator. Put this string to your emulator run command (or emulator arguments in EclipseIDE). The range is 0 -> 1000. Effective performance does not always scale in direct relationship with values.

Using "-netdelay <delayinMs> " to set the network latency. The default value is none.

Thứ Tư, 30 tháng 12, 2009

Android: Native Android Action

Native Android Action

Native Android applications allow Intents to launch Activities and Sub-Activities.
Actions list:
=> + content://contacts/people/1 -- Display information about the person whose identifier is "1".
=> + content://contacts/people/ -- Display a list of people, which the user can browse through.
=> +tel:123 -- Display the phone dialer with the given number filled in. Note how the VIEW action does what what is considered the most reasonable thing for a particular URI. => +content://contacts/people/1 -- Display the phone dialer with the person filled in.
=> +tel:123 -- Display the phone dialer with the given number filled in.

Thứ Ba, 29 tháng 12, 2009

Android: SharedPreferences

Shared Preferences
SharedPreferences let you save groups of key/value pairs of primitive data as named preferences. SharedPreferences is a lightweight mechanism to store a known set of values such as: user preferences, configuration, application settings...
The data which had created by SharedPreferences can be shared between applicaton components running in the same "Context".
Creating and Saving SharePreferences

//Define SharePreference Name
private static final String STRING_SHAREREF_NAME_USERREF = "USER REFERENCES";
//SharedPreferences object
private SharedPreferences mShareRefs = null;
//Create and save
protected void savePreferences() {
//get value from ui
boolean bAutoUpdate = mCbxAutoUpdate.isChecked();
int iFrequency = mSpinnerFrequency.getSelectedItemPosition();
int iMinMag = mSpinnerMinMagtitude.getSelectedItemPosition();

//Create SharedPreferences object
mShareRefs = getSharedPreferences(STRING_SHAREREF_NAME_USERREF,
Activity.MODE_PRIVATE);

//update to Preference by editor interface.
Editor editor = mShareRefs.edit();
editor.putBoolean(STRING_SHAREREF_USERREF_AUTOUPDATE, bAutoUpdate);
editor.putInt(STRING_SHAREREF_USERREF_FREQUENCYUPDATE, iFrequency);
editor.putInt(STRING_SHAREREF_USERREF_MINMAG, iMinMag);
editor.commit();
}
Notes:
- If you want to save information that doesn't need to be shared with others component, you can call Activity.getPreferences(Mode) without a specifying preference name.
(Activity).getPreferences(Activity.MODE_PRIVATE);

Retrieve the saved values:
SharedPreferences object offers some method to get persist data (type boolean, String, int, Long, ..):
  • getBoolean(..);
  • getInt(..);
  • getString(..);
  • ...


Ref:
- Pro Android June 2009
- Profession Android Application Development.

Android: Services

Because of the limited screen size of the mobile devices, typically only one application is visible and activate on device screen at any given time. Android offers Service class to create application components specifically to handle operation and functionality that should run silently, without a UserInterface. Android Services is higher priority than an inactive Activity, so they're less likely to be killed when the system requires resources. By using Service, you can ensure that applications continuous to run and response to events, even when they're inactive.

Android offers several techniques for application to communicate with users with an Activity providing a direct UserInterface, for ex: Notifications, Toast.
  • Toasts are a transient, non-modal Dialog-box mechanism used to display information to users without stealing focus from the active application.
  • Notifications represent a more robust mechanism for alerting users. Many users, when they're not actively using their mobile phones, they sit silent and unwatched in pocket or on a desk until it rings, vibrates or flashes. Should a user miss these alerts. This case, status bar icons are used to indicate that an event has occurred. All of these attention-grabbing antics are available within Android as Notifications.
  • Alarms provide a mechanism for fi ring Intents at set times, outside the control of your application lifecycle. An Alarm will fire even after its owner application has been closed, and can (if required) wake a device from sleep.
If your application regularly, or continuously, performs actions that don't depend directly from a user input, Services my be the answer. Start Service receive higher priority than inactive or invisible Activity, making them less likely to be terminated by run time's resource management. The only time Android will stop a Service prematurely is when it’s the only way for a foreground Activity to gain required resources; if that happens, your Service will be restarted automatically when resources become available.

Creating and Controlling Service
Services is extended from Service base class. Services are designed to run in the background, so they need to be started, stopped and controlled by other application component.

Notes:
- Once you've contructed a new Service, you have to register it in the application manifest file within the service tag:
...

(... to be continuous...)


Ref:
- Pro Android June 2009
- Profession Android Application Development.

Thứ Hai, 28 tháng 12, 2009

Android: Http Connection

This time, I'm going to building a service in Android. There are a lot of types of services with Android included: IPC (communication between applications on the same device), get resources outside the devices by various type of connections. I'll focus on Http connection first.
Although Android included web-browser application in the basic applications, but there are several benefits to creating thick and thin native application rather than relying on entirely web-base:
- Bandwidth
- Caching
- Native features.
With currently connection methods:
- GPRS, EDGE, 3G.
- Wi-Fi.
more details could collected from reference books below.

Connection permission for Android application
By Eclipse ADT plug-in:
- Open AndroidManifest.xml file (in design mode)
- Select "Permissions" tab ==> click "Add" and select "Uses permission"
- At the "Name" property, select "android.permission.INTERNET"
- Save setting.

By XML editor:
- Open AndroidManifest.xml file (in editor mode)
- Add below code:
Open an URL connection and get content:

public static String getHttpContent(String prURL) {
String strResult = "";
StringBuffer sbfResult = new StringBuffer();
String newline = System.getProperty("line.seperator");

try {
URL url = new URL(prURL);
URLConnection urlcon = url.openConnection();
HttpURLConnection httpurlcon = (HttpURLConnection) urlcon;

int responseCode = httpurlcon.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = httpurlcon.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = br.readLine()) != null) {
sbfResult.append(line).append(newline);
}
br.close();
in.close();
}
} catch (Exception e) {
sbfResult.append(e.getMessage()).append(newline);
}finally{
if (sbfResult != null) {
strResult = sbfResult.toString();
}else{
strResult = "StringBuffer has failed.";
}
}
return strResult;
}
}

Referenced:
- Pro Android June 2009
- Profession Android Application Development.

Thứ Năm, 24 tháng 12, 2009

Android: Overridable functions in Application's lifecycle

onSaveInstanceState
onSaveInstanceState() is called by Android if the Activity is being stopped and may be killed before it is resumed! This means it should store any state necessary to re-initialize to the same condition when the Activity is restarted. It is the counterpart to the onCreate() method, and in fact the savedInstanceState Bundle passed in to onCreate() is the same Bundle that you construct as outState in the onSaveInstanceState() method.

Thứ Tư, 23 tháng 12, 2009

Android: Introduction

What is Android ?
q
Is a Platform:
  • §Built on Linux kernel.
  • §For open handset devices.
  • §Open-source libraries for Web, SQLLite, OpenGL, SSL,…
Also included Middle-ware
  • §Base on C/C++ Linux kernel.
  • §Fully support for Java developer (by JNI).
  • §Use XML for flexible UI and Effect definition.
And is Key Applications with Android Software Stack
  • §Have a lot of applications fully support for PIM. (Contacts, Calendar, Phone, SMS Manager, Browser, Player, ..)

Android Application Software Stack
Slide 4
-
Linux Kernel 2.6 -Set of C/C++ open-source libraries had been converted to Java protocol for Java developer. -Surface Manager - manages access to the display subsystem and seamlessly composites 2D and 3D graphic layers from multiple applications -Android runtime with multi Dalvik VM instances and GC,.. Each Android Application (process) have it own Dalvik VM. -Application Framework: include so many services for management: - Content Providers: share data between components or applications. - Activity Manager: manages the lifecycle of applications and provides a common navigation back stack. (based on Android Software Stack) - Window Manager: - View System: Create interfaces for user. - Package Manager: manage installed applications, packages, librabries. - Telephony Manager: Phone’s services. - Resource Manager: providing access to non-code resources (strings, graphics, and layout files) - Location Manager: - Notification Manager: display custom alerts in the status bar. -APIs (JDK or NDK) for fully interacted with services and devices.
The Dalvik Virtual Machine
The Dalvik VM is a registered-base virtual machine. It is optimized for low memory requirements, and is designed to allow for multiple VM instances to run at once, relying on underlying operating system for process isolating, memory management and threading support. Dalvik use .dex files format:
A dx tool will compile Java class files to. dex file format. Multi classes are included in one .dex file, alls duplicate string or resource will be reduced for smallest size. Java byte codes are also converted into a alternative instruction set used by Dalvik VM. Dalvik executables may be modified again when they get installed onto a device.
Dalvik VM was slimmed down to use less space. Dalvik has modified constant pool to use only 32-bit indexes to simplify the interpreter. Dalvik VM use it own byte code, not Java byte code. The name “Dalvik” is belong to the name of a village in Iceland where Dan Bornstein’s ancestors lived. -The executable code on Android, as a result in Dalvik VM, is based not on Java byte code, but on .dex files format instead. -The java compiled class or .jar standard executable file are not compatible with Android. Why no “JIT” : Google has fine-tuned the garbage collection in the Dalvik VM, but it has chosen to omit a just-in-time (JIT) compiler, in this release at least. The company can justify this choice because many of Android’s core libraries, including the graphics libraries, are implemented in C and C++. For example, the Java graphics APIs are actually thin wrapper classes around the native code using the Java Native Interface (JNI). Similarly, Android provides an optimized C-based native library to access the SQLite database, but this library is encapsulated in a higher-level Java API. Because most of the core code is in C and C++, Google reasoned that the impact of JIT compilation would not be significant.

Thứ Năm, 17 tháng 12, 2009

Android: Error on missing resource

Now in Android - Eclipse IDE technique.
Have you ever got into an error like:

""is missing required source folder: 'gen'"
or this pic:


On Eclipse IDE, just right click and delete "gen" folder in your Package Explorer and Build project again. Got that ?

Gook luck,

Thứ Năm, 10 tháng 12, 2009

How to create a certificate with "makekeys"

Duty:
Create a self-sign certificate to sign on MIDlet, Symbian apps, Applet, .Net appls, ..

Resource: makekeys.exe executable file

Command:
%prompt%>makekeys -expdays 3650 -cert -password yourpassword -len 2048 -dname "CN=CertificateName OU=OrganizationUnit OR=ORganization CO=COuntry EM=yourEMail@now
here.com" keyfilename.key certificatefilename.cer


Result:
Reference from Symbian.com

Good luck!!

Thứ Ba, 8 tháng 12, 2009

Symbian - Carbide: Compilation Fails: Bareword Found Where Operator Expected (Wrong Active Perl version)

Compilation Fails: Bareword Found Where Operator Expected

Problem: When compiling an application, the process fails. The Problems view of Carbide.c++ reports that a .hlp.hrh file cannot be opened. In the Console view, problems with a Perl script are obvious (params.pm).

.hlp.hrh file cannot be opened
Problems with the perl script

Cause: The version of Perl on your system is newer than 5.6.x. The Symbian OS toolchain is not fully compatible to the 5.8.x/5.10.x release – you will probably not notice it for most projects, but, for example, compiling help files does not work with ActivePerl 5.8/5.10.

Solution: Either install Perl 5.6.1 , or follow the steps at http://wiki.forum.nokia.com/index.php/KIS001302_-_Compiling_context-sensitive_help_fails_with_latest_version_of_Perl:

Go to your SDK installation's "Epoc32\tools\perllib" path:

- Open file args.pm, change the following line (# 688)

$self->_iSpecArray->{$aName}= New CArgsSpec($aName, $aDefault, $aPattern,
$aExclusions, $aMandatory, $aRepeatable);

to

$self->_iSpecArray->{$aName}= CArgsSpec->New($aName, $aDefault, $aPattern,
$aExclusions, $aMandatory, $aRepeatable);

- Open file params.pm, search for the word "New" and replace it with "foo->New()"; for example, if there is a function "New CLogs()".

Reference from Developer.Symbian.com and Wiki.forum.nokia.com

Thứ Hai, 9 tháng 11, 2009