Pages

Tuesday, March 27, 2012

[Android] Create a dialog with list and EditText

You may have been able to create a dialog with list using AlertDialog,

you may also find some articles to make a dialog with a EditText.

But how if we can combine them?

I mean, isn't it better that we can create the dialog with several choices and  an "Other" choice to let the user enter their own answer in some cases?


In fact, the workaround is more simpler than I was thought, I just implement the onCreateDialog method to create a AlertDialog with several choices, and create another AlertDialog with another View contains an EditText if the user choose the "Other".

Here is my example:
I want to record the users' activity with time.
------------------------------------------------------------
public class WriteTagActivity extends Activity {
    private final String sOutFile = "XXX.txt";
    private final Context m_context = this;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //do some pre-process here
}

      
        Button tagButton = (Button) findViewById(R.id.tagButton);
        tagButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
               
                showDialog(0);
            }

        });
       
    }
   
    private void writeTag(String tag)
    {
        long curTime = System.currentTimeMillis() / 1000;

       
        String sCurTime = Long.toString(curTime);
        try {
            FileWriter fout = new FileWriter(sOutFile,true);
            fout.write(sCurTime + "," + tag + "\n");
            fout.close();
           
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
       
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        // TODO Auto-generated method stub
        final CharSequence[] tagList = {"party","dinner","exercising","studying","others(unrecommend)"};
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
       
        builder.setTitle("What are you doing now?");

       
        builder.setItems(tagList, new DialogInterface.OnClickListener() {
           
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                String tag = tagList[which].toString();
                String otherTags = tagList[tagList.length -1].toString();
                if(tag.compareTo(otherTags) == 0 )//custom tags
                {                       
                    createNewView();
                }
                else
                {
                    writeTag(tag);
                    Toast.makeText(m_context, "add " + tag + " to log...", Toast.LENGTH_SHORT).show();
                }
                   
            }
        });
       
       
        return builder.create();
    }
   

    private void createNewView()
    {
       
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
       
        builder.setTitle("What are you doing?");
   
        LayoutInflater inflater = LayoutInflater.from(m_context);
        final View otherTagView = inflater.inflate(R.layout.other_tag, null);
       
        final EditText tagEditText = (EditText) otherTagView.findViewById(R.id.tagEditText);

       
       
        builder.setPositiveButton("OK",new DialogInterface.OnClickListener(){

            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
       
                        String tag = tagEditText.getText().toString();
                        writeTag(tag);
                        Toast.makeText(m_context, "add " + tag + " to log...", Toast.LENGTH_SHORT).show();

            }
           
        }
        );
       
        builder.setView(otherTagView);
        builder.create();
        builder.show();
       
    }   
   
}

I just put a button in main.xml, and an EditText in other.tag.xml, if you really want them
other.tag.xml
---------------------
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >




    <EditText
        android:id="@+id/tagEditText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
---------------


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

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <Button
        android:id="@+id/tagButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Tag" />

</LinearLayout>
---------------------------


I won't talk about the detail for this stage due to my laziness...

[Android] Launch a service daily using AlarmManager

If you have heard crond in Linux kernel, AlarmManager is the counterpart in Android.



hint:  Activity can be regard as a foreground process.
         Service can be regard as a background process.

Task: Check something at everyday midnight automatically (User do not need to operate)

So, we need:
1. A Service that perform the task (in background). - CronService.java
2. An Activity that launch Service periodically. - CronTestActivity.java
3. Register the Service in Manifest.xml

Step 1. Create the Service you want:

public class CronService extends Service{
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);
       Toast.makeText(this, "Service start... ", Toast.LENGTH_SHORT).show();
    }
}

Step 2. Create the main activity and set up and schedule

public class CronTestActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Calendar cal= Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE,30);
        cal.set(Calendar.SECOND, 00);
     
       //Start the Service since today night, 11:30 p.m      

        Intent intent=  new Intent(this, CronService.class);
        PendingIntent pIntent = PendingIntent.getService(this,0, intent, 0);
       
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 24*60*60*1000, pIntent);

      //launch it every 24 hours
    }
}

step 3. Don't forget to register the Service in Manifest

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".CronTestActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
        <service android:name=".CronService"></service>
    </application>



By doing so, your process will be launched automatically every night since the user launch the app.
reference:
http://stackoverflow.com/questions/9004635/android-how-should-i-run-a-service-daily-and-12pm-using-alarmmanager

Monday, March 26, 2012

[Android] HTC desire S root

Desire 跟 Desire S不一樣,所以去找Desire的root法的下場就是浪費時間
首先要先security off,簡稱S-off

轉貼S-off教學

轉貼root中文教學

remove native apps on AVD
http://changyy.pixnet.net/blog/post/28872517

step 1: Install Superuser.apk.
step 2: Use Terminator to launch CLI on AVD.
step 3: Type su to get privilege.
step 4:  type mount -oremount,rw /dev/block/mtdblock0 /system, then do things you want.

Wednesday, March 21, 2012

[Android] How I launch other probes in Funf tutorial (wifiScanner)

<NOTICE>  I mean ADD, so check the format in your exist codes.

general speaking:
step 1. In MainActivity.java: launch probes in your service pool

 runOnceIntent.putExtra(MainPipeline.RUN_ONCE_PROBE_NAME, <your probe>.class.getName());
 startService(runOnceIntent); 

step 2. In Assets/default.json: set configuration of your probe
            "edu.mit.media.funf.probe.<your probe>": [
                {  }
            ],

step 3. In Manifest : set up your services:

 <service android:name="edu.mit.media.funf.probe.<your probe>"></service>

step 4. In Manifest : add the permission your probes need

    <uses-permission android:name="android.permission.<permission your probe need>" />

-----------------------------
Example:  add  BatteryProbe

1. In MainActivity.java
        Button scanNowButton = (Button)findViewById(R.id.scanNowButton);
        scanNowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent runOnceIntent = new Intent(context, MainPipeline.class);
                runOnceIntent.setAction(MainPipeline.ACTION_RUN_ONCE);
               
                runOnceIntent.putExtra(MainPipeline.RUN_ONCE_PROBE_NAME, WifiProbe.class.getName());
                startService(runOnceIntent);
                runOnceIntent.putExtra(MainPipeline.RUN_ONCE_PROBE_NAME, LocationProbe.class.getName());
                startService(runOnceIntent);
               
               
                runOnceIntent.putExtra(MainPipeline.RUN_ONCE_PROBE_NAME, BatteryProbe.class.getName());
                startService(runOnceIntent);
            }
        });
    }


step 2. In Assets/default.json
{       "name": "WifiScanner",
        "version":1,
        "dataArchivePeriod":3600,
        "dataRequests":{
            "edu.mit.media.funf.probe.builtin.LocationProbe": [
                { "PERIOD": 900, "DURATION": 30 }
            ],
            "edu.mit.media.funf.probe.builtin.WifiProbe": [
                { "PERIOD": 900 }
            ],
            "edu.mit.media.funf.probe.builtin.BatteryProbe": [
                { }
            ]


        }
}

step3. In Manifest : set up your services

        <service android:name="edu.mit.media.funf.probe.builtin.LocationProbe"></service>
        <service android:name="edu.mit.media.funf.probe.builtin.WifiProbe"></service>
        <service android:name="edu.mit.media.funf.probe.builtin.BatteryProbe"></service>

step4. In Manifest : add the permission your probes need
    <uses-permission android:name="android.permission.BATTERY_STATS" />
    <!-- All probes -->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
   
    <!-- Location probe -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  
   
    <!-- Wifi probe -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>



----------------

hint: Why I add that permission? check here: Funf wiki

Tuesday, March 20, 2012

[Android] Intent setAction

I am an absolutely newer to Android, and suffered while I developing a project using MIT Funf framework.

these several codes make me scratch my head.
----------------
final Context context = this;
Intent archiveIntent = new Intent(context, MainPipeline.class);
               
 archiveIntent.setAction(MainPipeline.ACTION_ARCHIVE_DATA);
 startService(archiveIntent);
----------------         

The most easy and precise explanation I have saw is:
http://milkmidi.blogspot.com/2012/02/android-intent.html (in Mandarin)

Monday, March 19, 2012

[Android] Resursively compress files in Android

References:
http://stackoverflow.com/questions/5414925/how-to-zip-folder-recursively-in-android
http://ucla.jamesyxu.com/?p=112

and I prefer this:
http://www.mkyong.com/java/how-to-compress-files-in-zip-format/


and I modified it a bit here:
-----------------------------------------------------------------
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class AppZip
{
   List<String> fileList;

   String SOURCE_FOLDER;
   String OUTPUT_ZIP_FILE;

   AppZip(String SOURCE_FOLDER, String OUTPUT_ZIP_FILE){
       this.SOURCE_FOLDER = SOURCE_FOLDER;
       this.OUTPUT_ZIP_FILE = OUTPUT_ZIP_FILE;
       fileList = new ArrayList<String>();
       generateFileList(new File(SOURCE_FOLDER));
   }

 

   /**
    * Zip it
    * @param zipFile output ZIP file location
    */
   public void zipIt(){

    String zipFile = this.OUTPUT_ZIP_FILE;
    byte[] buffer = new byte[1024];

    try{

       FileOutputStream fos = new FileOutputStream(zipFile);
       ZipOutputStream zos = new ZipOutputStream(fos);

       System.out.println("Output to Zip : " + zipFile);

       for(String file : this.fileList){

           System.out.println("File Added : " + file);
           ZipEntry ze= new ZipEntry(file);
           zos.putNextEntry(ze);

           FileInputStream in =
                      new FileInputStream(SOURCE_FOLDER + File.separator + file);

           int len;
           while ((len = in.read(buffer)) > 0) {
               zos.write(buffer, 0, len);
           }

           in.close();
       }

       zos.closeEntry();
       //remember close it
       zos.close();

       System.out.println("Done");
   }catch(IOException ex){
      ex.printStackTrace();  
   }
  }

   /**
    * Traverse a directory and get all files,
    * and add the file into fileList 
    * @param node file or directory
    */
   public void generateFileList(File node){

       //add file only
    if(node.isFile()){
        fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
    }

    if(node.isDirectory()){
        String[] subNote = node.list();
        for(String filename : subNote){
            generateFileList(new File(node, filename));
        }
    }

   }

   /**
    * Format the file path for zip
    * @param file file path
    * @return Formatted file path
    */
   private String generateZipEntry(String file){
       return file.substring(SOURCE_FOLDER.length(), file.length());
   }
}
--------------------------------------
example:
String myFiles = "C:\\myfiles\\"; //do not forgot the backslash in this version
String  outZipName = "compressedFiles"; //compressedFile.zip
AppZip az = new AppZip(myFiles, outZipName);
az.zipIt();




non-recursive version:
http://stackoverflow.com/questions/8409219/zipping-files-and-folders-in-android

Thursday, March 1, 2012

[Java] Recursive listFiles with filter

 /** original: http://snippets.dzone.com/posts/show/1875
*
*    
*    modified by Spencer, Mar. 1, 2012
*    overload member function listfiles: directory name and extension are also acceptable.
*/
import java.io.*;
import java.util.*;
public class FileRecursor
{
public static File[] listFilesAsArray(
        File directory,
        FilenameFilter filter,
        boolean recurse)
{
    Collection<File> files = listFiles(directory,
            filter, recurse);
//Java4: Collection files = listFiles(directory, filter, recurse);
   
    File[] arr = new File[files.size()];
    return files.toArray(arr);
}

public static File[] listFilesAsArray(
        final String sDirectory,
        final String sFilter,
        boolean recurse)
{
    File directory = new File(sDirectory);
    FilenameFilter filter = new FilenameFilter()
    {
        public boolean accept(File dir, String name)
        {
             return name.endsWith(sFilter);
         }
    };
    Collection<File> files = listFiles(directory,
            filter, recurse);
//Java4: Collection files = listFiles(directory, filter, recurse);
   
    File[] arr = new File[files.size()];
    return files.toArray(arr);
}

public static Collection<File> listFiles(
// Java4: public static Collection listFiles(
        File directory,
        FilenameFilter filter,
        boolean recurse)
{
    // List of files / directories
    Vector<File> files = new Vector<File>();
// Java4: Vector files = new Vector();
   
    // Get files / directories in the directory
    File[] entries = directory.listFiles();
   
    // Go over entries
    for (File entry : entries)
    {
// Java4: for (int f = 0; f < files.length; f++) {
// Java4:     File entry = (File) files[f];

        // If there is no filter or the filter accepts the
        // file / directory, add it to the list
        if (filter == null || filter.accept(directory, entry.getName()))
        {
            files.add(entry);
        }
       
        // If the file is a directory and the recurse flag
        // is set, recurse into the directory
        if (recurse && entry.isDirectory())
        {
            files.addAll(listFiles(entry, filter, recurse));
        }
    }
   
    // Return collection of files
    return files;       
}
}

////////////

Example:     
//list the .java files under the current directory
File[] filelist = new FileRecursor().listFilesAsArray("./" ,".java", true);
for(File f:filelist)
   System.out.println(f.getName());