MyFlexRadio App Released on the Android Market

No Comments

MyFlexRadio has been published on the Android Market and is officially affiliated with MyFlexRadio.com. Go get it!

MyFlexRadio
MyFlexRadio

Lock Screen
Lock Screen Replacement

chronix Radio

No Comments

chronix Radio has been published on the Android Market and is officially affiliated with chroniX Radio. Go get it!

chronix Radio
chroniX Radio

Lock Screen
Lock Screen Replacement

Android Bartender released

No Comments

Android Bartender is little drink recipe search engine app I put together for fun. It has 32,479 drink recipes that are search-able by name or ingredient. Drink recipes can be shared by any means supported by your phone… email, messaging, facebook, twitter, etc.

Check it out: Android Bartender on appbrain.com

Announcing andAMP (Android Awesome Music Player) Beta!

2 Comments

I am proud to announce the public beta of andAMP (Android Awesome Music Player). This full featured music player is my idea of what a media player should be. It is simple to use and has all of the features you should ever need in a music player application… but I have more features planned and hope to make andAMP one of the best music player applications available on the market.

Features

  • Simple to use interface – manage everything from a single location rather than 5 different windows for everything
  • Full playlist support with playlists available as regular albums… even with customizable cover images!
  • Retrieve missing album covers from the internet (Google Images)
  • ID3 Tag Editor for single songs or complete albums
  • Party Shuffle Mode – continuous playback of random songs from your whole collection
  • Shuffle Mode – shuffle playback of songs within your playlist or current play queue
  • Song Search – know the name of the song but can’t remember what album it’s in? This simple search solves that problem.
  • Song Mode – if you just want to listen to songs as you click on them… this mode is for you.
  • Attractive cover scroller… kind of like coverflow but not :)
  • Current song indicators – First, the song that is playing will have a little speaker next to it… secondly, the player will automatically select the album that the song is from.
  • Continuous Play – select continuous play to play the same list or song over and over
  • Mostly bug free! :) Look… every application on the planet has issues every once in awhile but we have done everything we can to test every feature… help us out and find bugs!

Screenshots

andAMP Interface

andAMP Interface

More andAMP Interface

Play Queue

Save Queue to Playlist

Song ID3 Tag Editor

Album ID3 Tag Editor (mass editor)

Song Search

Song Search Results

Album Menu (Long Press Album Cover)

Change Album Cover from Google Images Search

Playlist Menu (Long Press Playlist Cover)

Playlist Default Cover

Playlist with a custom Cover

You can Download the Beta Here:

Download andAMP from AndroidWorkz
Download andAMP from Android Market

Source Code: Find files by type + play media file

No Comments

I was perusing StackOverflow for Android items and came across this question Getting the Contents of a Specific Directory on the SDCard. I love StackOverflow… but for some reason I can’t post xml code examples and the code field doesn’t always work currently so you end up with code outside of the code box…. So, anyway, I decided to make an example for Edward and post it here so that everything would be formatted correctly.

This examples focus is the FileUtils class that I created for the purpose of finding files recursively on the SD Card. Here is the class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class FileUtils {

    public File[] listFilesAsArray(File directory, FilenameFilter[] filter,
            int recurse) {
        Collection<File> files = listFiles(directory, filter, recurse);

        File[] arr = new File[files.size()];
        return files.toArray(arr);
    }

    public Collection<File> listFiles(File directory,
            FilenameFilter[] filter, int recurse) {

        Vector<File> files = new Vector<File>();

        File[] entries = directory.listFiles();

        if (entries != null) {
            for (File entry : entries) {
                for (FilenameFilter filefilter : filter) {
                    if (filter == null
                            || filefilter
                                    .accept(directory, entry.getName())) {
                        files.add(entry);
                        Log.v("FileUtils", "Added: "
                                + entry.getName());
                    }
                }
                if ((recurse <= -1) || (recurse > 0 && entry.isDirectory())) {
                    recurse--;
                    files.addAll(listFiles(entry, filter, recurse));
                    recurse++;
                }
            }
        }
        return files;
    }
}

Edward needs to find files by type (specifically ringtones) from a path… either on the phone (as in the following example) or on the SD Card. He could use the MediaStore.Audio.Media Content Provider to accomplish this task… however, it would give him all of the audio media on the phone. It is sometimes necessary to list files by a particular mimetype without using the Content Providers. In my example, this is accomplished by using a list of file extensions and searching the desired path for files that match those file extensions. There are two ways you could go about it… you could make a String[] array of the extensions or you could use the Resources array as I have done. Below is the xml for the mimetypes we are looking for.

/res/values/mimetypes.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="audio">
<item>aif</item>
<item>aifc</item>
<item>aiff</item>
<item>au</item>
<item>mid</item>
<item>mp3</item>
<item>ogg</item>
<item>snd</item>
<item>wav</item>
</string-array>
</resources>

Using a Resources string array is very convenient and provides a way for you to store arrays in files so that you can use them on demand rather than keeping them in memory. They are very simple to use. In my example you can see how they are used in the FindFiles function as seen here:

1
2
3
4
Resources resources = getResources();
// array of valid audio file extensions
String[] audioTypes = resources.getStringArray(R.array.audio);
FilenameFilter[] filter = new FilenameFilter[audioTypes.length];

Of particular interest in the above example is the FilenameFilter object. This allows us to define an array of file extension filters that works very quickly and only returns the files we want.

Here is the example application that I created for Edward. It lists all of the audio files in /system/media/audio/ringtones/ and displays them in a ListView. When you click a particular file in the ListView it starts playing. There is a menu item to stop the ringtone from playing (there seems to be an issue with MediaPlayer.setLooping(false) when dealing with ogg files) and to quit the application. The complete Eclipse project is available for download at the bottom of the post.

/res/layout/main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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">
    <ListView android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:drawSelectorOnTop="false" />
    <TextView android:id="@android:id/empty"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="No ringtones found." />
</LinearLayout>

/res/layout/list_item.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="@+id/ringtone"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="40dip"
    android:textSize="18dip"
    android:textStyle="bold"
    android:textColor="#FFFFE0" />


/src/com/androidworks/findfiles/FindFilesByType.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
package com.androidworkz.findfiles;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.res.Resources;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;

public class FindFilesByType extends ListActivity {

    private static final int EXIT = 0;
    private static final int STOP = 1;
    private static final String DIRECTORY = "/system/media/audio/ringtones/";
    private MediaPlayer mp = new MediaPlayer();
    List<String> Ringtones = new ArrayList<String>();
    Boolean hasErrors = false;
    int currentPosition = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ListView lv = getListView();
        File ringtones_directory = new File(DIRECTORY);
        if (!ringtones_directory.exists()) {
            AlertDialog.Builder ad = new AlertDialog.Builder(
                    FindFilesByType.this);
            ad.setTitle("Directory Not Found");
            ad.setMessage("Sorry! The ringtones directory doesn't exist.");
            ad.setPositiveButton("OK", null);
            ad.show();
            hasErrors = true;
        }
       
        if (!ringtones_directory.canRead()) {
            AlertDialog.Builder ad = new AlertDialog.Builder(
                    FindFilesByType.this);
            ad.setTitle("Permissions");
            ad.setMessage("Sorry! You don't have permission to list the files in that folder");
            ad.setPositiveButton("OK", null);
            ad.show();
            hasErrors = true;
        }
        else {
            Ringtones = FindFiles(false);

            if (Ringtones.size() < 1) {
                AlertDialog.Builder ad = new AlertDialog.Builder(
                        FindFilesByType.this);
                ad.setTitle("Permissions");
                ad.setMessage("Sorry! No ringtones exists in " + DIRECTORY + ".");
                ad.setPositiveButton("OK", null);
                ad.show();
                Log.e("Ringtones", "No ringtones were found.");
                hasErrors = true;
            }
        }      
       
        if (!hasErrors) {
            setListAdapter(new ArrayAdapter<String>(FindFilesByType.this, R.layout.list_item,
                    Ringtones));
           
            lv.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> aView, View v,
                        int position, long id) {
                    currentPosition = position;
                    playRingtone(DIRECTORY+Ringtones.get(position));
                }
            });
        }
    }
   
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
       
        int NONE = Menu.NONE;
        if (mp.isPlaying()) {
            menu.add(NONE, STOP, 0, "Stop");
        }
        menu.add(NONE, EXIT, 1, "Exit");
        return true;
    }
   
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case STOP:
            mp.stop();
            break;
        case EXIT:
            quit();
            break;
        }

        return super.onOptionsItemSelected(item);
    }

    private void playRingtone(String ringtone) {
        try {
            mp.reset();
            mp.setDataSource(ringtone);
            mp.prepare();
            mp.start();
        } catch (IOException e) {
            Log.v("Ringtone", e.getMessage());
        }
    }

    private List<String> FindFiles(Boolean fullPath) {
        final List<String> tFileList = new ArrayList<String>();
        Resources resources = getResources();
        // array of valid audio file extensions
        String[] audioTypes = resources.getStringArray(R.array.audio);
        FilenameFilter[] filter = new FilenameFilter[audioTypes.length];

        int i = 0;
        for (final String type : audioTypes) {
            filter[i] = new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    return name.endsWith("." + type);
                }
            };
            i++;
        }

        FileUtils fileUtils = new FileUtils();
        File[] allMatchingFiles = fileUtils.listFilesAsArray(
                new File(DIRECTORY), filter, -1);
        for (File f : allMatchingFiles) {
            if (fullPath) {
                tFileList.add(f.getAbsolutePath());
            }
            else {
                tFileList.add(f.getName());
            }
        }
        return tFileList;
    }

    public class FileUtils {

        public void saveArray(String filename, List<String> output_field) {
            try {
                FileOutputStream fos = new FileOutputStream(filename);
                GZIPOutputStream gzos = new GZIPOutputStream(fos);
                ObjectOutputStream out = new ObjectOutputStream(gzos);
                out.writeObject(output_field);
                out.flush();
                out.close();
            } catch (IOException e) {
                e.getStackTrace();
            }
        }

        @SuppressWarnings("unchecked")
        public List<String> loadArray(String filename) {
            try {
                FileInputStream fis = new FileInputStream(filename);
                GZIPInputStream gzis = new GZIPInputStream(fis);
                ObjectInputStream in = new ObjectInputStream(gzis);
                List<String> read_field = (List<String>) in.readObject();
                in.close();
                return read_field;
            } catch (Exception e) {
                e.getStackTrace();
            }
            return null;
        }

        public File[] listFilesAsArray(File directory, FilenameFilter[] filter,
                int recurse) {
            Collection<File> files = listFiles(directory, filter, recurse);

            File[] arr = new File[files.size()];
            return files.toArray(arr);
        }

        public Collection<File> listFiles(File directory,
                FilenameFilter[] filter, int recurse) {

            Vector<File> files = new Vector<File>();

            File[] entries = directory.listFiles();

            if (entries != null) {
                for (File entry : entries) {
                    for (FilenameFilter filefilter : filter) {
                        if (filter == null
                                || filefilter
                                        .accept(directory, entry.getName())) {
                            files.add(entry);
                            Log.v("FileUtils", "Added: "
                                    + entry.getName());
                        }
                    }
                    if ((recurse <= -1) || (recurse > 0 && entry.isDirectory())) {
                        recurse--;
                        files.addAll(listFiles(entry, filter, recurse));
                        recurse++;
                    }
                }
            }
            return files;
        }
    }
   
    public void quit() {
        int pid = android.os.Process.myPid();
        android.os.Process.killProcess(pid);
        System.exit(0);
    }
}

Here is a screenshot:

You can download the Eclipse Project Here: Download FindFilesByType.zip

Source Code: ImageView Flipper + SD Card Scanner

No Comments

This is a little project I have been working on that is based on code that I found at codeshogun.com for working with the ViewFlipper. If you are looking for a sample project that incorporates the ViewFlipper to scroll through images or if you are looking for a sample project for how to recursively search the SD Card for files based on type (or any other type of file searching for that matter) than this project might help. This is open source with no license whatsoever… so you can use it however you like. This project also features something I haven’t seen in other projects and that is how to save an array object to a file and read it back in. It works very quickly and it is a fast way to save data instances without messing with a database or serialization. The reason I used it was to save the data so that the application wouldn’t attempt to rescan the SD Card whenever the screen orientation changed (something I hate about Android). This also shows you how to save variable state using SharedPreferences. You can download a zip of the Eclipse project at the bottom of the post.

The layout – /res/layout/main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/flipper"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
       
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center">      
        <ImageView
            android:id="@+id/zero"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="centerInside"
            android:src="@drawable/wait"
        />
    </LinearLayout>
   
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center">
        <ImageView
            android:id="@+id/one"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="centerInside"
            android:src="@drawable/wait"
        />
    </LinearLayout>
   
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center">
        <ImageView
            android:id="@+id/two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="centerInside"
            android:src="@drawable/wait"
        />
    </LinearLayout>
   
</ViewFlipper>

A string array /res/values/mimetypes.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="image">
<item>bmp</item>
<item>cmx</item>
<item>cod</item>
<item>gif</item>
<item>ico</item>
<item>ief</item>
<item>jpe</item>
<item>jpeg</item>
<item>jpg</item>
<item>jfif</item>
<item>pbm</item>
<item>pgm</item>
<item>png</item>
<item>pnm</item>
<item>ppm</item>
<item>ras</item>
<item>rgb</item>
<item>svg</item>
<item>tif</item>
<item>tiff</item>
<item>xbm</item>
<item>xpm</item>
<item>xwd</item>
</string-array>
</resources>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
package com.androidworkz.imageviewflipper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import android.app.Activity;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.ViewFlipper;

public class ImageViewFlipper extends Activity {
   
    private static final int EXIT = 0;
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private static final String DIRECTORY = "/sdcard/";
    private static final String DATA_DIRECTORY = "/sdcard/.ImageViewFlipper/";
    private static final String DATA_FILE = "/sdcard/.ImageViewFlipper/imagelist.dat";
    private GestureDetector gestureDetector;
    View.OnTouchListener gestureListener;
    private Animation slideLeftIn;
    private Animation slideLeftOut;
    private Animation slideRightIn;
    private Animation slideRightOut;
    private ViewFlipper viewFlipper;
    private int currentView = 0;
    List<String> ImageList;
    private int currentIndex = 0;
    private int maxIndex = 0;

    FileOutputStream output = null;
    OutputStreamWriter writer = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
       
        setContentView(R.layout.main);
        ImageView iv = (ImageView) findViewById(R.id.zero);

        File data_directory = new File(DATA_DIRECTORY);
        if (!data_directory.exists()) {
            if (data_directory.mkdir()) {
                FileUtils savedata = new FileUtils();
                Toast toast = Toast.makeText(ImageViewFlipper.this,
                        "Please wait while we search your SD Card for images...", Toast.LENGTH_SHORT);
                toast.show();
                SystemClock.sleep(100);
                ImageList = FindFiles();
                savedata.saveArray(DATA_FILE, ImageList);
               
            } else {
                ImageList = FindFiles();
            }

        }
        else {
            File data_file= new File(DATA_FILE);
            if (!data_file.exists()) {
                FileUtils savedata = new FileUtils();
                Toast toast = Toast.makeText(ImageViewFlipper.this,
                        "Please wait while we search your SD Card for images...", Toast.LENGTH_SHORT);
                toast.show();
                SystemClock.sleep(100);
                ImageList = FindFiles();
                savedata.saveArray(DATA_FILE, ImageList);
            } else {
                FileUtils readdata = new FileUtils();
                ImageList = readdata.loadArray(DATA_FILE);
            }
        }
       
        if (ImageList == null) {
            quit();
        }
       
        SharedPreferences indexPrefs = getSharedPreferences("currentIndex",
                MODE_PRIVATE);
        if (indexPrefs.contains("currentIndex")) {
            currentIndex = indexPrefs.getInt("currentIndex", 0);
        }
       
        maxIndex = ImageList.size() - 1;
       
        Log.v("currentIndex", "Index: "+currentIndex);

        viewFlipper = (ViewFlipper) findViewById(R.id.flipper);

        slideLeftIn = AnimationUtils.loadAnimation(this, R.anim.slide_left_in);
        slideLeftOut = AnimationUtils
                .loadAnimation(this, R.anim.slide_left_out);
        slideRightIn = AnimationUtils
                .loadAnimation(this, R.anim.slide_right_in);
        slideRightOut = AnimationUtils.loadAnimation(this,
                R.anim.slide_right_out);

        viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
                android.R.anim.fade_in));
        viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
                android.R.anim.fade_out));
       
        iv.setImageDrawable(Drawable.createFromPath(ImageList
                .get(currentIndex)));
        System.gc();
       
        gestureDetector = new GestureDetector(new MyGestureDetector());
        gestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (gestureDetector.onTouchEvent(event)) {
                    return true;
                }
                return false;
            }
        };

    }
   
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
       
        int NONE = Menu.NONE;
        menu.add(NONE, EXIT, NONE, "Exit");
        return true;
    }
   
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case EXIT:
            quit();
            break;
        }

        return super.onOptionsItemSelected(item);
    }
   
    protected void onPause() {
        super.onPause();

        SharedPreferences indexPrefs = getSharedPreferences("currentIndex",
                MODE_PRIVATE);
       
        SharedPreferences.Editor indexEditor = indexPrefs.edit();
        indexEditor.putInt("currentIndex", currentIndex);
        indexEditor.commit();
    }
   
    protected void onResume() {
        super.onResume();
        SharedPreferences indexPrefs = getSharedPreferences("currentIndex",
                MODE_PRIVATE);
        if (indexPrefs.contains("currentIndex")) {
            currentIndex = indexPrefs.getInt("currentIndex", 0);
        }  
    }

    private List<String> FindFiles() {
        final List<String> tFileList = new ArrayList<String>();
        Resources resources = getResources();
        // array of valid image file extensions
        String[] imageTypes = resources.getStringArray(R.array.image);
        FilenameFilter[] filter = new FilenameFilter[imageTypes.length];

        int i = 0;
        for (final String type : imageTypes) {
            filter[i] = new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    return name.endsWith("." + type);
                }
            };
            i++;
        }

        FileUtils fileUtils = new FileUtils();
        File[] allMatchingFiles = fileUtils.listFilesAsArray(
                new File(DIRECTORY), filter, -1);
        for (File f : allMatchingFiles) {
            tFileList.add(f.getAbsolutePath());
        }
        return tFileList;
    }

    public class FileUtils {
       
        public void saveArray(String filename, List<String> output_field) {
             try {
                FileOutputStream fos = new FileOutputStream(filename);
                GZIPOutputStream gzos = new GZIPOutputStream(fos);
                ObjectOutputStream out = new ObjectOutputStream(gzos);
                out.writeObject(output_field);
                out.flush();
                out.close();
             }
             catch (IOException e) {
                 e.getStackTrace();
             }
          }

          @SuppressWarnings("unchecked")
        public List<String> loadArray(String filename) {
              try {
                FileInputStream fis = new FileInputStream(filename);
                GZIPInputStream gzis = new GZIPInputStream(fis);
                ObjectInputStream in = new ObjectInputStream(gzis);
                List<String> read_field = (List<String>)in.readObject();
                in.close();
                return read_field;
              }
              catch (Exception e) {
                  e.getStackTrace();
              }
              return null;
          }
         
        public File[] listFilesAsArray(File directory, FilenameFilter[] filter,
                int recurse) {
            Collection<File> files = listFiles(directory, filter, recurse);

            File[] arr = new File[files.size()];
            return files.toArray(arr);
        }

        public Collection<File> listFiles(File directory,
                FilenameFilter[] filter, int recurse) {

            Vector<File> files = new Vector<File>();

            File[] entries = directory.listFiles();

            if (entries != null) {
                for (File entry : entries) {
                    for (FilenameFilter filefilter : filter) {
                        if (filter == null
                                || filefilter
                                        .accept(directory, entry.getName())) {
                            files.add(entry);
                            Log.v("ImageViewFlipper", "Added: "
                                    + entry.getName());
                        }
                    }
                    if ((recurse <= -1) || (recurse > 0 && entry.isDirectory())) {
                        recurse--;
                        files.addAll(listFiles(entry, filter, recurse));
                        recurse++;
                    }
                }
            }
            return files;
        }
    }

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
                // right to left swipe
                if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                        && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    viewFlipper.setInAnimation(slideLeftIn);
                    viewFlipper.setOutAnimation(slideLeftOut);

                    if (currentIndex == maxIndex) {
                        currentIndex = 0;
                    } else {
                        currentIndex = currentIndex + 1;
                    }
                    if (currentView == 0) {
                        currentView = 1;
                        ImageView iv = (ImageView) findViewById(R.id.one);
                        iv.setImageDrawable(Drawable.createFromPath(ImageList
                                .get(currentIndex)));
                        System.gc();
                    } else if (currentView == 1) {
                        currentView = 2;
                        ImageView iv = (ImageView) findViewById(R.id.two);
                        iv.setImageDrawable(Drawable.createFromPath(ImageList
                                .get(currentIndex)));
                        System.gc();
                    } else {
                        currentView = 0;
                        ImageView iv = (ImageView) findViewById(R.id.zero);
                        iv.setImageDrawable(Drawable.createFromPath(ImageList
                                .get(currentIndex)));
                        System.gc();
                    }
                    Log.v("ImageViewFlipper", "Current View: " + currentView);
                    viewFlipper.showNext();
                } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                        && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    viewFlipper.setInAnimation(slideRightIn);
                    viewFlipper.setOutAnimation(slideRightOut);
                    if (currentIndex == 0) {
                        currentIndex = maxIndex;
                    } else {
                        currentIndex = currentIndex - 1;
                    }
                    if (currentView == 0) {
                        currentView = 2;
                        ImageView iv = (ImageView) findViewById(R.id.two);
                        iv.setImageDrawable(Drawable.createFromPath(ImageList
                                .get(currentIndex)));
                    } else if (currentView == 2) {
                        currentView = 1;
                        ImageView iv = (ImageView) findViewById(R.id.one);
                        iv.setImageDrawable(Drawable.createFromPath(ImageList
                                .get(currentIndex)));
                    } else {
                        currentView = 0;
                        ImageView iv = (ImageView) findViewById(R.id.zero);
                        iv.setImageDrawable(Drawable.createFromPath(ImageList
                                .get(currentIndex)));
                    }
                    Log.v("ImageViewFlipper", "Current View: " + currentView);
                    viewFlipper.showPrevious();
                }
            } catch (Exception e) {
                // nothing
            }
            return false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (gestureDetector.onTouchEvent(event))
            return true;
        else
            return false;
    }
   
    public void quit() {
        SharedPreferences indexPrefs = getSharedPreferences("currentIndex",
                MODE_PRIVATE);
       
        SharedPreferences.Editor indexEditor = indexPrefs.edit();
        indexEditor.putInt("currentIndex", 0);
        indexEditor.commit();
       
        File settings = new File(DATA_FILE);
        settings.delete();
        finish();
        int pid = android.os.Process.myPid();
        android.os.Process.killProcess(pid);
        System.exit(0);
    }
}

You can download the Eclipse Project Here: Download ImageViewFlipper.zip

Developers: Use System Explorer to select directories or files

No Comments

I have added PICK_FILE and PICK_DIRECTORY intents to System Explorer so that developers can use it to select files or directories. You can also pass the file name or directory to open and System Explorer will start there.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 /**
 * Opens System Explorer to open a file.
 */

private static final int REQUEST_RESULT = 1;

private void openFile(String fileName) {   
    Intent intent = new Intent("com.androidworkz.action.PICK_FILE");
   
    // Construct URI from file name.
    intent.setData(Uri.parse("file://" + fileName));
    intent.putExtra("com.androidworkz.extra.TITLE", "Select a file to open");
    intent.putExtra("com.androidworkz.extra.BUTTON_TEXT", "Open");
   
    try {
        startActivityForResult(intent, REQUEST_RESULT);
    } catch (ActivityNotFoundException e) {
        e.printStackTrace();
        Toast.makeText(this, "System Explorer is not installed", Toast.LENGTH_SHORT).show();
    }
}

/**
 * Opens System Explorer to open a directory.
 */

private void openDirectory(String directoryName) { 
    Intent intent = new Intent("com.androidworkz.action.PICK_DIRECTORY");
   
    // Construct URI from file name.
    intent.setData(Uri.parse("file://" + directoryName));
   
    // Set fancy title and button (optional)
    intent.putExtra("com.androidworkz.extra.TITLE", getString(R.string.pick_directory_title));
    intent.putExtra("com.androidworkz.extra.BUTTON_TEXT", getString(R.string.pick_directory_button));
   
    try {
        startActivityForResult(intent, REQUEST_RESULT);
    } catch (ActivityNotFoundException e) {
        e.printStackTrace();
        Toast.makeText(this, "System Explorer is not installed", Toast.LENGTH_SHORT).show();
    }
}

/**
 * This is called when the user has selected the file or directory and clicked a button to return to your application.
 */

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    switch (requestCode) {
    case REQUEST_RESULT:
        if (resultCode == RESULT_OK && intent != null) {
            // obtain the filename
            String filename = intent.getDataString();
            if (filename != null) {
                // Get rid of URI prefix:
                if (filename.startsWith("file://")) {
                    filename = filename.substring(7);
                }
                // Do something with the file here
            }      
        }
        break;
    }
}

System Explorer Updated

No Comments

I upgraded System Explorer this morning.

What’s New

  • Users can now send files via email – tested with Gmail
  • Fixed a couple of bugs with the menu context
  • Added tabs to the bottom of the window
  • Added Help
  • Added Quit button

Get it here: AppBrain or here: Android Market

System Explorer Released!

No Comments

Today we have launched our first application on the Android Market. It is a full featured file manager with built in text editor, image viewer and zip utility.

Features

  • File Manager
  • Text Editor
  • Image Viewer
  • Zip Utility
  • Install APK files from your SD Card
  • Open Media Files from your SD Card
  • Copy, Cut, Paste, Delete files from your SD Card

Indication of things to come?

No Comments

Another huge difference between the iPhone OS and Android is the development cycle. I don’t know Objective C but I can’t imagine that it is easier to write applications in than Java and if the truth be told when I was looking through the documentation for Objective C it gave me a headache. From a career standpoint, it doesn’t make any sense for me to learn a language that I see as proprietary… it’s the same reason I don’t code in Visual Basic or J++. I CAN learn to do it if I want… because almost all object oriented programming languages share the same basic principles… it’s only a matter of learning syntax (which can be helped by syntax hinting in most good IDE’s). This brings us to a possibly revealing announcement yesterday from Layar that has shocked alot of people.

Amsterdam, June 2nd 2010. Today Layar introduces a new way to browse with the latest Layar Reality Browser (version 3.5). The rapid growth of content within Layar increases the need for real time location based search. With the new version of the browser users can now easily discover and experience Augmented Reality without the need to enter a search query or open a specific layer. Users will immediately see the most interesting content nearby whenever they open the Layar Reality Browser, taking Augmented Reality from novelty to utility.

What’s interesting about this announcement is that if you visit their site and read the press release you find this:

Layar Reality Browser version 3.5 with Stream Technology is available now for download in the Android Market. The iPhone release will be available soon.

So basically, they have released the Android version but not an iPhone version yet… since the release is merely an update for an application that is already on the iPhone apps market they don’t have to wait for approval… so that leads to the speculation that seems logical. It’s easier to develop applications for Android and they released the application that was completed while they are continuing development on the iPhone version. What do you think happened?

Layar’s Reality Browser revolutionizes mobile content discovery, by simply presenting the most interesting mobile content based on a user’s location & preferences. When launching the Layar Reality Browser users will be presented with a dynamic list of the most interesting content at their location. The list is sorted by time, location, proximity, popularity and preferences. The benefit of a list is that discovery is now possible without the need to hold the device up. It lowers the threshold to find interesting content, encouraging daily use.

About Layar
Layar is the world’s leading Augmented Reality Platform and browser on mobile. The Layar Reality Browser has more than 2 million users and serves 2.4 million augmented objects every day. The browser comes pre-installed on tens of millions of phones from leading handset manufacturers and carriers by the end of the year.

Over 700 layers are published on the Layar Platform with over 2500 in development. These layers are developed by the global community of 3500 Layar publishers and producers, and by leading brands and agencies. Layar is located in Amsterdam, The Netherlands. The company is VC funded and has 32 employees.

The free Layar Reality Browser is available on Android devices and iPhone 3GS. The Layar Platform is available for anyone to create their own Augmented Reality experiences on.