Saturday, February 23, 2019

10 apps you should make when learning mobile programme


If you are learning mobile programme, you can build many apps for yourself. Here are 10 apps that almost everyone can do, some already have detail guide.
1 – Book reading
Reading book app is the most classical app on mobile phone. We change word documents to txt file and use Java InputStream to read. This is simplest and useful app that you must do first.
2 – Music listener
We can make a music listen app for our self. It is simple and easy like read book app. Just put some lines of code in to a class and done. See this post for more details.
3 – Weather information
If you want to check weather in certain city, make a weather app for yourself. Download Android Studio or Eclipse and see this post. If you want to run continuously on home screen or just outside lock screen, you can find easy way to do from this blog.
4 –  Get RSS Feed news
You can read online latest news by create an app to get RSS Feed from a site that you like. Read this post.
5 – Lunar calendar
To make a lunar calendar app, download Java programme to change solar day to lunar day, the author is Mr. Ho Ngoc Duc, he give it free.
The rest is presented as a table of numbers from 1-31 depending on the month on an interface with 7 columns. This is not difficult, just know what the first day of a particular year is, the days before or after that will go ahead or continuously.
6 –  Compass
If you like fengshui, you need a compass to detect your house degree. Just use Google search the code, change to whatever you want, and run it on to a mobile phone that have magnetic sensor. Swift compass you can see here.
7 – Ruler
Many developers like to make a ruler app, we can use it to measure the size of small things. In canvas, we draw lines with 1 millimet dimension. To make it accurate, we need to know phone ‘s physical dimension. Android can‘t  do that in code, so we create a spinner to let user choose screen size. Swift ruler here.
8 – Football update
If you like football, we can make an app to get result and rank update of the football tournament we like. We get RSS Feed from a site with acceptable fee, our app use this to work.
9 – Alarm wake clock
If you don’t like the wake sound of default clock in your phone, just make it yourself, copy sound file to raw folder and use broadcast to set wake time. More detail in this post.
10 –  Fengshui apps

Many peoples like fengshui, they want to know their lucks every year. We can search online all necessary informations and change them to txt file, find beautiful icons to decorate and make an app.

Get RSS Feed news app

We will create an android rss feed example app that get RSS Feed news from REUTERS, CNN and BBC.
Create a project name getnet, package name is com.example.getnet, add permission in to file Manifest.xml.
<uses-permission android:name="android.permission.INTERNET" />
MinSDK from 8.
Add these lines in to class Main declaration.
android:screenOrientation="portrait"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
Use this link to download http client package.
In Eclipse, right click on to project, Build Path, Configure Build Path, Add External JARs, open download folder, lib, choose all jars file,  OK.


Create a class name NewsItemFactory.
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class NewsItemFactory {
    public static class NewsItem {
        public String title;
        public String link;
        public String description;
       
        @Override
        public String toString() {
            return title;
        }
    }
   
    public static List<NewsItem> parseFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
        List<NewsItem> items = new ArrayList<NewsItem>();
       
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
               
            if (parser.getName().equals("rss") ||
                    parser.getName().equals("channel")) {
                //Skip these items, but allow to drill inside
            } else if (parser.getName().equals("item")) {
                NewsItem newsItem = readItem(parser);
                items.add(newsItem);
            } else {
                //Skip any other elements and their children
                skip(parser);
            }
        }
       
        return items;
    }
   
private static NewsItem readItem(XmlPullParser parser) throws XmlPullParserException, IOException {
        NewsItem newsItem = new NewsItem();
        //Must start with an <item> element to be valid
        parser.require(XmlPullParser.START_TAG, null, "item");
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
           
            String name = parser.getName();
            if (name.equals("title")) {
                parser.require(XmlPullParser.START_TAG, null, "title");
                newsItem.title = readText(parser);
                parser.require(XmlPullParser.END_TAG, null, "title");
            } else if (name.equals("link")) {
                parser.require(XmlPullParser.START_TAG, null, "link");
                newsItem.link = readText(parser);
                parser.require(XmlPullParser.END_TAG, null, "link");               
            } else if (name.equals("description")) {
                parser.require(XmlPullParser.START_TAG, null, "description");
                newsItem.description = readText(parser);
                parser.require(XmlPullParser.END_TAG, null, "description");
            } else {
                //Skip any other elements, and their children
                skip(parser);
            }
        }
       
        return newsItem;
    }
   
    private static String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
        String result = "";
        if (parser.next() == XmlPullParser.TEXT) {
            result = parser.getText();
            parser.nextTag();
        }
        return result;
    }
   
private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
            throw new IllegalStateException();
        }
       
int depth = 1;
        while (depth != 0) {
            switch (parser.next()) {
            case XmlPullParser.END_TAG:
                depth--;
                break;
            case XmlPullParser.START_TAG:
                depth++;
                break;
            }
        }
    }
}
Create a class name RestTask.
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.List;

import android.os.AsyncTask;
import android.util.Log;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpResponseException;


public class RestTask extends AsyncTask<Void, Integer, Object> {
    private static final String TAG = "RestTask";

    public interface ResponseCallback {
        public void onRequestSuccess(String response);

        public void onRequestError(Exception error);
    }

    public interface ProgressCallback {
        public void onProgressUpdate(int progress);
    }
   
    private HttpURLConnection mConnection;
    private String mFormBody;
    private File mUploadFile;
    private String mUploadFileName;
    private WeakReference<ResponseCallback> mResponseCallback;
    private WeakReference<ProgressCallback> mProgressCallback;

    public RestTask(HttpURLConnection connection) {
        mConnection = connection;
    }

    public void setFormBody(List<NameValuePair> formData) {
        if (formData == null) {
            mFormBody = null;
            return;
        }
       
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < formData.size(); i++) {
            NameValuePair item = formData.get(i);
            sb.append( URLEncoder.encode(item.getName()) );
            sb.append("=");
            sb.append( URLEncoder.encode(item.getValue()) );
            if (i != (formData.size() - 1)) {
                sb.append("&");
            }
        }

        mFormBody = sb.toString();
    }

    public void setUploadFile(File file, String fileName) {
        mUploadFile = file;
        mUploadFileName = fileName;
    }

    public void setResponseCallback(ResponseCallback callback) {
        mResponseCallback = new WeakReference<ResponseCallback>(callback);
    }

    public void setProgressCallback(ProgressCallback callback) {
        mProgressCallback = new WeakReference<ProgressCallback>(callback);
    }

    private void writeMultipart(String boundary, String charset, OutputStream output, boolean writeContent) throws IOException {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(output, Charset.forName(charset)), 8192);
            // Post Form Data Component
            if (mFormBody != null) {
                writer.write("--" + boundary);
                writer.write("\r\n");
                writer.write("Content-Disposition: form-data; name=\"parameters\"");
                writer.write("\r\n");
                writer.write("Content-Type: text/plain; charset=" + charset);
                writer.write("\r\n");
                writer.write("\r\n");
                if (writeContent) {
                    writer.write(mFormBody);
                }
                writer.write("\r\n");
                writer.flush();
            }
            // Send binary file.
            writer.write("--" + boundary);
            writer.write("\r\n");
            writer.write("Content-Disposition: form-data; name=\"" + mUploadFileName
                            + "\"; filename=\"" + mUploadFile.getName() + "\"");
            writer.write("\r\n");
            writer.write("Content-Type: "
                            + URLConnection.guessContentTypeFromName(mUploadFile
                                            .getName()));
            writer.write("\r\n");
            writer.write("Content-Transfer-Encoding: binary");
            writer.write("\r\n");
            writer.write("\r\n");
            writer.flush();
            if (writeContent) {
                InputStream input = null;
                try {
                    input = new FileInputStream(mUploadFile);
                    byte[] buffer = new byte[1024];
                    for (int length = 0; (length = input.read(buffer)) > 0;) {
                        output.write(buffer, 0, length);
                    }
                    // Don't close the OutputStream yet
                    output.flush();
                } catch (IOException e) {
                    Log.w(TAG, e);
                } finally {
                    if (input != null) {
                        try {
                            input.close();
                        } catch (IOException e) {
                        }
                    }
                }
            }
            // This CRLF signifies the end of the binary data chunk
            writer.write("\r\n");
            writer.flush();

            // End of multipart/form-data.
            writer.write("--" + boundary + "--");
            writer.write("\r\n");
            writer.flush();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    private void writeFormData(String charset, OutputStream output) throws IOException {
        try {
            output.write(mFormBody.getBytes(charset));
            output.flush();
        } finally {
            if (output != null) {
                output.close();
            }
        }
    }

    @Override
    protected Object doInBackground(Void... params) {
        //Generate random string for boundary
        String boundary = Long.toHexString(System.currentTimeMillis());
        String charset = Charset.defaultCharset().displayName();
       
        try {
            // Set up output if applicable
            if (mUploadFile != null) {
                //We must do a multipart request
                mConnection.setRequestProperty("Content-Type",
                        "multipart/form-data; boundary=" + boundary);
                //Calculate the size of the extra metadata
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                writeMultipart(boundary, charset, bos, false);
                byte[] extra = bos.toByteArray();
                int contentLength = extra.length;
                //Add the file size to the length
                contentLength += mUploadFile.length();
                //Add the form body, if it exists
                if (mFormBody != null) {
                    contentLength += mFormBody.length();
                }
                mConnection.setFixedLengthStreamingMode(contentLength);
            } else if (mFormBody != null) {
                //In this case, it is just form data to post
                mConnection.setRequestProperty("Content-Type",
                                "application/x-www-form-urlencoded; charset=" + charset);
                mConnection.setFixedLengthStreamingMode(mFormBody.length());
            }
           
            //This is the first call on URLConnection that actually
            // does Network IO.  Even openConnection() is still just
            // doing local operations.
            mConnection.connect();

            // Do output if applicable (for a POST)
            if (mUploadFile != null) {
                OutputStream out = mConnection.getOutputStream();
                writeMultipart(boundary, charset, out, true);
            } else if (mFormBody != null) {
                OutputStream out = mConnection.getOutputStream();
                writeFormData(charset, out);
            }

            // Get response data
            int status = mConnection.getResponseCode();
            if (status >= 300) {
                String message = mConnection.getResponseMessage();
                return new HttpResponseException(status, message);
            }

            InputStream in = mConnection.getInputStream();
            String encoding = mConnection.getContentEncoding();
            int contentLength = mConnection.getContentLength();
            if (encoding == null) {
                encoding = "UTF-8";
            }

            byte[] buffer = new byte[1024];

            int length = contentLength > 0 ? contentLength : 0;
            ByteArrayOutputStream out = new ByteArrayOutputStream(length);

            int downloadedBytes = 0;
            int read;
            while ((read = in.read(buffer)) != -1) {
                downloadedBytes += read;
                publishProgress((downloadedBytes * 100) / contentLength);
                out.write(buffer, 0, read);
            }

            return new String(out.toByteArray(), encoding);
        } catch (Exception e) {
            Log.w(TAG, e);
            return e;
        } finally {
            if (mConnection != null) {
                mConnection.disconnect();
            }
        }
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        // Update progress UI
        if (mProgressCallback != null && mProgressCallback.get() != null) {
            mProgressCallback.get().onProgressUpdate(values[0]);
        }
    }

    @Override
    protected void onPostExecute(Object result) {
        if (mResponseCallback != null && mResponseCallback.get() != null) {
            if (result instanceof String) {
                mResponseCallback.get().onRequestSuccess((String) result);
            } else if (result instanceof Exception) {
                mResponseCallback.get().onRequestError((Exception) result);
            } else {
                mResponseCallback.get().onRequestError(new IOException("Unknown Error Contacting Host"));
            }
        }
    }
}
Create a class name RestUtil.
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import org.apache.http.NameValuePair;
import android.util.Base64;

public class RestUtil {
   
    public static RestTask obtainGetTask(String url)
            throws MalformedURLException, IOException {
        HttpURLConnection connection = (HttpURLConnection) (new URL(url))
                .openConnection();

        connection.setReadTimeout(10000);
        connection.setConnectTimeout(15000);
        connection.setDoInput(true);

        RestTask task = new RestTask(connection);
        return task;
    }

    public static RestTask obtainAuthenticatedGetTask(String url,
            String username, String password) throws MalformedURLException, IOException {
        HttpURLConnection connection = (HttpURLConnection) (new URL(url))
                .openConnection();

        connection.setReadTimeout(10000);
        connection.setConnectTimeout(15000);
        connection.setDoInput(true);
       
        attachBasicAuthentication(connection, username, password);
       
        RestTask task = new RestTask(connection);
        return task;
    }
   
    public static RestTask obtainFormPostTask(String url,
            List<NameValuePair> formData) throws MalformedURLException,
            IOException {
        HttpURLConnection connection = (HttpURLConnection) (new URL(url))
                .openConnection();

        connection.setReadTimeout(10000);
        connection.setConnectTimeout(15000);
        connection.setDoOutput(true);

        RestTask task = new RestTask(connection);
        task.setFormBody(formData);

        return task;
    }
   
    public static RestTask obtainAuthenticatedFormPostTask(String url,
            List<NameValuePair> formData, String username, String password) throws MalformedURLException,
            IOException {
        HttpURLConnection connection = (HttpURLConnection) (new URL(url))
                .openConnection();

        connection.setReadTimeout(10000);
        connection.setConnectTimeout(15000);
        connection.setDoOutput(true);
       
        attachBasicAuthentication(connection, username, password);

        RestTask task = new RestTask(connection);
        task.setFormBody(formData);

        return task;
    }

    public static RestTask obtainMultipartPostTask(String url,
            List<NameValuePair> formPart, File file, String fileName)
            throws MalformedURLException, IOException {
        HttpURLConnection connection = (HttpURLConnection) (new URL(url))
                .openConnection();

        connection.setReadTimeout(10000);
        connection.setConnectTimeout(15000);
        connection.setDoOutput(true);

        RestTask task = new RestTask(connection);
        task.setFormBody(formPart);
        task.setUploadFile(file, fileName);

        return task;
    }

    private static void attachBasicAuthentication(URLConnection connection, String username, String password) {
        //Add Basic Authentication Headers
        String userpassword = username + ":" + password;
        String encodedAuthorization = Base64.encodeToString(userpassword.getBytes(), Base64.NO_WRAP);
        connection.setRequestProperty("Authorization", "Basic "+
              encodedAuthorization);
    }

}
In layout folder, create a file name lim.xml like this.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="40sp"
    android:orientation="horizontal" >
    <TextView
        android:id="@+id/tem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="3sp"
        android:gravity="center_vertical"
        android:textColor="#4B4542"
        android:textSize="15sp" />
</RelativeLayout>
File activity_main.xml look like this.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:background="#ffffff"
    tools:context="com.example.getnet.MainActivity" >

    <LinearLayout
        android:id="@+id/tem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/t"
            android:layout_width="80dp"
            android:layout_height="45dp"
            android:layout_gravity="center"
            android:clickable="true"
            android:gravity="center"
            android:onClick="on"
            android:textColor="#00f"
            android:textSize="17sp" />

        <TextView
            android:id="@+id/t2"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:clickable="true"
            android:gravity="center"
            android:onClick="on2"
            android:textColor="#0000cd"
            android:textSize="17sp" />

</LinearLayout>

    <ListView
        android:id="@+id/li"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@+id/tem"
        android:layout_gravity="center" >
    </ListView>

</RelativeLayout>
Class MainActivity like this.
import java.io.StringReader;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.getnet.NewsItemFactory.NewsItem;
import com.example.getnet.RestTask.ResponseCallback;

public class MainActivity extends Activity implements ResponseCallback {
    private static final String TAG = "FeedReader";
    
      String FEED_URI = "http://feeds.reuters.com/reuters/entertainment";
    
     private ListView mList;
     private ArrayAdapter<NewsItem> mAdapter;
     private ProgressDialog mProgress;
     TextView t,t2;
    
     @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        t = (TextView) findViewById(R.id.t3);
        t.setText("CNN");
        t2 = (TextView) findViewById(R.id.t4);
        t2.setText("BBC");
        mList = (ListView) findViewById(R.id.li);
      
        mAdapter = new ArrayAdapter<NewsItem>(this, R.layout.lim, R.id.tem);
        mList.setAdapter( mAdapter);
        mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                NewsItem item = mAdapter.getItem(position);
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse(item.link));
                startActivity(intent);
            }
        });
    }
     public void on2(View v){
          FEED_URI = "http://feeds.bbci.co.uk/vietnamese/rss.xml";
          try{
             RestTask task = RestUtil.obtainGetTask(FEED_URI);
             task.setResponseCallback(this);
             task.execute();
             mProgress = ProgressDialog.show(this, "Searching", "Waiting For Results...", true);
         } catch (Exception e) {
             Log.w(TAG, e);
         }
     }
     public void on(View v){
         
          FEED_URI = "http://rss.cnn.com/rss/cnn_latest.rss";
          try{
             RestTask task = RestUtil.obtainGetTask(FEED_URI);
             task.setResponseCallback(this);
             task.execute();
             mProgress = ProgressDialog.show(this, "Searching", "Waiting For Results...", true);
         } catch (Exception e) {
             Log.w(TAG, e);
         }
     }
    
@Override
    public void onResume() {
        super.onResume();
    //Retrieve the RSS feed
        try{
            RestTask task = RestUtil.obtainGetTask(FEED_URI);
            task.setResponseCallback(this);
            task.execute();
            mProgress = ProgressDialog.show(this, "Searching", "Waiting For Results...", true);
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }
   
    @Override
    public void onRequestSuccess(String response) {
        if (mProgress != null) {
            mProgress.dismiss();
            mProgress = null;
        }
        //Process the response data
        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(new StringReader(response));
            //Jump to the first tag
            parser.nextTag();
           
            mAdapter.clear();
            for(NewsItem item : NewsItemFactory.parseFeed(parser)) {
                mAdapter.add(item);
            }
            mAdapter.notifyDataSetChanged();
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }
   
    @Override
    public void onRequestError(Exception error) {
        if (mProgress != null) {
            mProgress.dismiss();
            mProgress = null;
        }
        //Display the error
        mAdapter.clear();
        mAdapter.notifyDataSetChanged();
        Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
    }
}

Run to see the result.