PERSONAL MEDIA CLOUD APPLICATION FOR ANDROID

Prajakta Sarurkar B.E., Nagpur University, 2000

PROJECT

Submitted in partial satisfaction of the requirements for the degree of

MASTER OF SCIENCE

in

COMPUTER SCIENCE

at

CALIFORNIA STATE UNIVERSITY, SACRAMENTO

SPRING 2012

© 2012

Prajakta Sarurkar ALL RIGHTS RESERVED

ii

PERSONAL MEDIA CLOUD APPLICATION FOR ANDROID

A Project

by

Prajakta Sarurkar

Approved by:

______, Committee Chair Du Zhang, Ph.D.

______, Second Reader Mary Jane Lee, Ph.D.

______Date

iii

Student: Prajakta Sarurkar

I certify that this student has met the requirements for format contained in the University format manual, and that this project is suitable for shelving in the Library and credit is to be awarded for the project.

______, Graduate Coordinator ______Nikrouz Faroughi, Ph.D. Date

Department of Computer Science

iv

Abstract

of

PERSONAL MEDIA CLOUD APPLICATION FOR ANDROID

by

Prajakta Sarurkar

Recent advances in communication technologies have enabled an exponential growth in connected devices like Android smart phones and tablets. These devices are mainly used for content consumption. However, limited resources available on these devices, as well as always connected internet accessibility makes these devices ideal platforms for .

This project is an attempt at creating personal media cloud player app for Android smart phone devices. The project uses off the shelf hardware components for private cloud implementation and Java programming over Android to provide full featured media cloud platform. This private media cloud enables users to:

 Store media files (images/audio/video etc) in the cloud

 Access the media files from their Android device

Additionally, the project aims at providing following features:

 File browsing

 Audio streaming (MP3)

 Video streaming (MP4)

v

 Images (JPEG/PNG)

 e-radio/ Photo Slide Show

The project aims at developing an application that can be used by any Android (version

2.2 and higher) smartphone to implement above mentioned media functionality.

, Committee Chair Du Zhang, Ph.D.

______Date

vi

DEDICATION

To my family

vii

ACKNOWLEDGEMENTS

I would like to thank my project advisor Dr. Du Zhang for taking time and giving me guidance through the project.

I would also like to thank all the professors who taught me during my masters’ course work.

I would like to thank my family for all the support.

viii

TABLE OF CONTENTS

Dedication ...... vii

Acknowledgements ...... viii

Table Of Contents ...... ix

List Of Figures ...... xii

List Of Tables ...... xiii

1 INTRODUCTION ...... 1

1.1 Current state of practice for Media Cloud ...... 1

1.2 Scope of the project ...... 2

1.3 Benefits of Media Cloud App ...... 3

2 BACKGROUND ...... 5

2.1 Current existing Cloud Media Storage ...... 5

2.2 Cloud Fundamentals ...... 8

2.3 Cloud APIs ...... 12

2.4 Android Apps ...... 14

2.5 Android application components ...... 17

2.5.1 Activities ...... 17

2.5.2 Services ...... 18

2.5.3 Content providers ...... 18

2.5.4 Broadcast receivers ...... 19

3 ARCHITECTURE AND TECHNOLOGY ...... 21

ix

3.1 Basic Architecture of Media Player app ...... 21

3.2 Features ...... 22

3.3 Application ...... 23

4 IMPLEMENTATION DETAILS ...... 25

4.1 Media cloud ...... 25

4.2 Android APIs ...... 28

4.3 Android client ...... 30

4.3.1 Login Screen ...... 30

4.3.2 Main Screen ...... 31

4.3.3 File View ...... 32

4.3.4 Music player...... 33

4.3.5 Image Viewer ...... 34

4.3.6 Video player ...... 35

4.3.7 File Uploading ...... 36

5 PERFORMANCE EVALUATION ...... 37

6 CONCLUSION AND FUTURE WORK ...... 39

6.1 Future work ...... 39

6.1.1 Playlist Management ...... 39

6.1.2 File Sharing ...... 39

6.1.3 Folder sync up ...... 40

x

Appendix Source Code ...... 41

Bibliography ...... 97

xi

LIST OF FIGURES

Page

Figure 1: Typical cloud configuration ...... 9

Figure 2: Cloud storage setup using Pogoplug ...... 11

Figure 3: Architecture of Pogoplug device ...... 12

Figure 4: Architecture of Cloud Media player app ...... 22

Figure 5: Control flow in Cloud Media player app...... 24

Figure 6: Login Screen...... 31

Figure 7: Main Screen ...... 32

Figure 8: File view ...... 33

Figure 9: (A) - Audio player screen, (B) – Radio player screen ...... 34

Figure 10: (A) - Image diaglog , (B) – Loaded image ...... 35

Figure 11: File uploading ...... 36

xii

LIST OF TABLES

Page

Table 1: Media formats supported by Media Cloud App ...... 2

Table 2: Comparative study of various cloud implementations ...... 6

Table 3: Pogoplug Specifications ...... 11

Table 4: Pogoplug APIs ...... 27

Table 5: Android APIs ...... 29

Table 6: Media Cloud app performance evaluation ...... 38

xiii 1

Chapter 1

INTRODUCTION

Smartphones along with Tablet computers are turning out to be the ―next big thing‖ in crowded electronic gadget industry [1]. Customizable features, powerful gesture based user interface, and always ON connectivity are the key features that are resulting in widespread popularity of smartphone devices. Smartphones are also responsible for growing interest in cloud computing, especially in the domain of media consumption [2,

3]. Always ON internet connectivity allows users to easily access data from remote servers in the cloud [4]. This enables users to easily store digital multi-media in the cloud and access them from anywhere, anytime.

1.1 Current state of practice for Media Cloud

Feature rich Android Smartphones and Tablet computers have enabled a wide range of applications and new usage models, including cloud based applications. However, use of cloud based media storage is becoming popular only after faster connection speeds offered by 3G and 4G communication networks. Some applications such as Pandora and

You Tube do exist that allow cloud like media streaming but these applications can only stream content available on respective web sites and not personal collection.

Recently companies such as and Apple have made media cloud service available

[5, 6] but these are targeted towards media purchased on the Amazon or iTunes respectively. Apple’s iCloud does allow uploading personal files but it is more expensive

2 than having personal cloud device. Currently, there are a few applications available that will allow users to access their personal cloud storage using their smartphone devices.

1.2 Scope of the project

This project aims at setting up a personal media cloud [17] using standard off the shelf components. Additionally, the project aims at developing an Android app that will enable

Android Smartphones and Tablet computers to access the media stored on cloud and allows media playback.

Media Type Format File Type Details

Mono/Stereo, AAC/HE- Audio .3gp/.mp4 Bit rates up to AACv1/HE-AACv2 160kHz

Mono/Stereo,

Audio MP3 .mp3 bit rates 8-

320k

MIDI Type 0 Audio MIDI .mid and Type 1

Image JPEG/GIF/PNG/BMP .jpg/.gif//.png/.bmp

Video H.263 .3gp/.mp4

Table 1: Media formats supported by Media Cloud App

3

The media app will support following features:

 File browsing

 Image Viewer

 Audio Playback

 Video Playback

Media app will allow streaming media over internet. Table 1 shows media formats that will be supported by the app.

1.3 Benefits of Media Cloud App

Growing popularity of Android Smartphones and Tablet computers is helping cloud based data storage to grow popular as well. Morevoer, in today’s digital world people are increasingly finding ways to store the media in cloud. Cloud storage also allows people to easily share their personal media. Media cloud app allows users to easily access media stored in their personal cloud device using Android smartphones and tablets. It will also address shortcomings in currently available media cloud app such as video streaming, file upload, photo slideshow, e-radio etc.

Rest of this report is divided in several chapters. Chapter 2 includes the background information on cloud storage as well as Android apps. Detailed information on setting up cloud storage and Android application development is presented. Chapter 3 includes the architecture and features of the Media Cloud App. Chapter 4 includes implementation

4 details of different modules of the Media Cloud App. Chapter 5 includes the performance evaluation of the Media Cloud App. Chapter 6 includes the conclusion and future work.

5

Chapter 2

BACKGROUND

Chapter 1 discussed the need for an Android app that supports cloud based media storage.

This chapter provides background information including cloud fundamentals as well

Android app development.

2.1 Current existing Cloud Media Storage

Media centric cloud computing is rapidly evolving field and a number of advances are happening in this area [4]. Table 2 shows the comparative details about various clouds available to users. Most noteworthy are Apple’s iCloud [4], Amazon cloud media player

[5], Zumodrive [7], and Pogoplug [10]. iCloud is a well integrated cloud service with Apple. This service is integrated with various Apple devices such iPhone, iPod, iMac etc. This service allows user to store media such as photos, music and documents, in addition to apps, calendar etc. However iCloud does not support video streaming.

6

CRITERIA ICLOUD AMAZON ZUMO POGOPLUG

DRIVE

Cloud Commercial Commercial SW Cloud Cloud App

Type Cloud Service Cloud Service adapter

Storage Up to 100GB Up to 1TB Depends on Depends on HD

Limit HD

Cost/GB $2/year (for $1/year (for ~ $2/year plus ~10¢ fixed cost

100GB) 1TB) Hardware cost (for 2TB)

(for 500GB)

Services Apps, Music, Music storage, Music, picture Store any type

Photo, Docs streaming storage, of file, Audio

streaming

Advantages Integrated Integrated with Integrates Low cost,

with Apps Amazon with iTunes, standard based

Picasa interfaces

Limitations No Video No Video No Video No Automatic

Streaming Streaming Streaming Sync

No Video

streaming

Table 2: Comparative study of various cloud implementations

7

Amazon, the largest online retailer recently announced online media storage service with a cloud media player for Android devices. The newly launched service will help users in storing application, songs and other digital media, and will also enable Android users to stream music stored on the Amazon servers with a Cloud Drive Player application. The application supports most commonly used file types, including AAC and MP3, and streams the media back at the full bit rate of the original file. Cloud media player supports some common controls like play, pause, skip and users can even build their own playlists. However, this service will not support video streaming. Moreover, uploading music from mobile device is not currently supported, although music files may be uploaded from PC or Mac. This solution also does not support syncing media files from device to the cloud.

ZumoDrive is a cloud media storage solution that supports devices running Android 1.6 and later versions. Users install the ZumoDrive application on their PC computer which enables them to access media files such as music and photos using the ZumoDrive app on

Android device. ZumoDrive supports sharing any type of media file, however this solution does not support video streaming. This solution also does not support syncing media files from device to the cloud.

Pogoplug cloud app is used to connect with Pogoplug cloud adapter. Pogoplug cloud adapter allows users to connect their own hard disk drives to cloud. Users can then access these hard drives on their Android Smartphones and Tablet computers using Pogoplug

8 cloud app. Pogoplug cloud app lacks certain features such as video streaming, automatic file sync, photo slide show, and e-Radio.

2.2 Cloud Fundamentals

Cloud is the term used to describe servers connected to internet such that client applications can interact with the servers and storage as long as internet connectivity can be guaranteed [8].

Perosnal media cloud refers to a small server in a home or small business network that can be accessed over the Internet. Designed for sharing photos and videos, personal clouds enable viewing and streaming from any Internet-connected personal computer and from Android smartphones [17].

Typical cloud configuration is shown in Figure 1. As shown, a cloud system consists of a server connected to the internet via high speed link. The server may also be connected to a mass storage system, such as a hard drive. A client such as a smartphone or any device capable of connecting to internet can then communicate with the server [9]. In this configuration, the server may provide either computing services or storage services or a combination of both. Present project requires the server to provide storage and media streaming services. Sometimes user can connect their own hard disk drives to the server to form personal media cloud systems.

9

STORAGE

SERVER

Cloud

CLIENT

Figure 1: Typical cloud configuration

Cloud systems are characterized with 4 properties [9, 16]:

1. Consistency: Ability of a computer-related hardware or software component

to consistently perform according to its specifications

10

2. Availability: Ability of the system to perform work when it is expected to

perform work

3. Partition Tolerance: Ability of the system to perform in the event of arbitrary

message loss or failure of part of the system

4. Response Time: Time taken to complete requested operation

With these criteria in mind, a search for suitable hardware devices was conducted. A number of devices were studied, including,

 Iomega iConnect Wireless Data Station

 Verbatim MediaShare Mini Home Network Storage

 Seagate FreeAgent GoFlex Net Media Sharing Device

 Western Digital My Book Live Personal Cloud Storage Device

 Cirago Network USB Storage Link

 Pogoplug

The device named pogoplug was selected, mainly due to the open source software components and ability to interface with third party software [10].

Pogoplug is a multimedia sharing device from CloudEngines that acts as a server connecting to any external hard drive using USB ports. Typical cloud storage setup using pogoplug is shown in Figure 2 [11]. Once the hard drive connection over USB port is setup, the content on hard driver can be accessed and shared over the internet. Pogoplug works across multiple platforms and allows streaming videos, music and photos without any monthly fees [10]. Pogoplug specifications are indicated in Table 1 [12].

11

Figure 2: Cloud storage setup using Pogoplug

Parameter Specification

Power Requirements 100-240V, 50-60Hz

Hard drive USB 2.0 connection

File System Formats NTFS, FAT32, Mac OS Extended Journaled and non-

Journaled (HFS+), EXT-2/EXT-3

Network Connection Gigabit Ethernet

Operating Systems MS Windows XP, Vista, Windows 7, Mac OSX 10.5 and

above (Intel and PowerPC) 32bit kernel only,

Web Browsers Safari, FireFox 3, IE 7, IE 8, Google Chrome

Web APIs Javascript, Java, PHP, .NET, C++

Table 3: Pogoplug Specifications

12

2.3 Cloud APIs

As mentioned in earlier section, primary reason we selected Pogoplug device to implement cloud storage is because the device is based on open architecture. Internal architecture of Pogoplug device is shown in Figure 3. As shown, Pogoplug device is a

Linux machine based on ARM compatible processor [12].

POGOPLUG API

LINUX OS

HARDWARE ABSTRACTION AND DRIVERS

NETWORK CONTROLLER ARM CPU HDD/USB CONTROLLER

Gigabit Ethernet USB ports for HDDs

Figure 3: Architecture of Pogoplug device

13

All Pogoplug API methods support HTTP (and HTTPS) protocol transport mechanisms.

The API has been designed to transparently support both REST style and SOAP style

HTTP calling conventions. All responses to API call requests are either raw data responses or structured responses depending on the API call in question. Structured responses are provided in either SOAP, Simple XML, or JSON format depending on the arguments used to invoke the API call [13].

All API method calls are supported through a base URL such as: http://service.pogoplug.com/svc/api

Invoking methods are performed with URLs constructed by the following pattern: http://service.pogoplug.com/svc/api[/format][/methodName]

Where format is optional response format (e.g. soap, xml, json) and methodName is the name of the method to be invoked. As an example, invoking the method getVersion would be performed on any of the following URLs: http://service.pogoplug.com/svc/api/getVersion http://service.pogoplug.com/svc/api/xml/getVersion http://service.pogoplug.com/svc/api/json/getVersion http://service.pogoplug.com/svc/api/soap/getVersion

The argument calling convention is implied by the HTTP request type. An HTTP GET request to the URL will imply a REST style call with arguments passed on the query string in standard browser form query string encoding. Thus, for example, invoking method loginUser can be performed with a REST style call by performing an HTTP GET on the following URL:

14 http://service.pogoplug.com/svc/api/[email protected]&p assword=test

Similarly, an HTTP POST request to the URL will imply a SOAP style call with arguments encoded inside a SOAP XML envelope passed as the request body of the

HTTP request.

The response format is implied based on the calling convention or specified specifically in the URL. The implied response for REST style requests is JSON, and the implied response for SOAP style requests is SOAP.

Exceptions can be returned from any API call rather than the structured response that was expected. Exceptions will always be of the same form and encode some level of useful information for converting to a user presentation error message.

Exceptions will be returned with HTTP 500 level response codes in the HTTP header.

2.4 Android Apps

Android applications are written in the Java programming language [14]. The Android

SDK tools compile the code—along with any data and resource files—into an Android package, an archive file with an .apk suffix. All the code in a single .apk file is considered to be one application and is the file that Android-powered devices use to install the application.

Once installed on a device, each Android application lives in its own security sandbox:

 The Android is a multi-user Linux system in which each

application is a different user.

15

 By default, the system assigns each application a unique Linux user ID (the ID is

used only by the system and is unknown to the application). The system sets

permissions for all the files in an application so that only the user ID assigned to

that application can access them.

 Each process has its own virtual machine (VM), so an application's code runs in

isolation from other applications.

 By default, every application runs in its own Linux process. Android starts the

process when any of the application's components need to be executed, then shuts

down the process when it's no longer needed or when the system must recover

memory for other applications.

In this way, the Android system implements the principle of least privilege. That is, each application, by default, has access only to the components that it requires to do its work and no more. This creates a very secure environment in which an application cannot access parts of the system for which it is not given permission.

However, there are ways for an application to share data with other applications and for an application to access system services:

It's possible to arrange for two applications to share the same Linux user ID, in which case they are able to access each other's files. To conserve system resources, applications with the same user ID can also arrange to run in the same Linux process and share the same VM (the applications must also be signed with the same certificate).

16

An application can request permission to access device data such as the user's contacts,

SMS messages, the mountable storage (SD card), camera, Bluetooth, and more. All application permissions must be granted by the user at install time.

A unique aspect of the Android system design is that any application can start another application’s component [15]. For example, if you want the user to capture a photo with the device camera, there's probably another application that does that and your application can use it, instead of developing an activity to capture a photo yourself. You don't need to incorporate or even link to the code from the camera application. Instead, you can simply start the activity in the camera application that captures a photo. When complete, the photo is even returned to your application so you can use it. To the user, it seems as if the camera is actually a part of your application.

When the system starts a component, it starts the process for that application (if it's not already running) and instantiates the classes needed for the component. For example, if your application starts the activity in the camera application that captures a photo, that activity runs in the process that belongs to the camera application, not in your application's process. Therefore, unlike applications on most other systems, Android applications don't have a single entry point (there's no main() function, for example).

Because the system runs each application in a separate process with file permissions that restrict access to other applications, your application cannot directly activate a component from another application. The Android system, however, can. So, to activate a component

17 in another application, you must deliver a message to the system that specifies your intent to start a particular component. The system then activates the component for you.

2.5 Android application components

Application components are the essential building blocks of an Android application [15].

Each component is a different point through which the system can enter your application.

Not all components are actual entry points for the user and some depend on each other, but each one exists as its own entity and plays a specific role—each one is a unique building block that helps define your application's overall behavior.

There are four different types of application components. Each type serves a distinct purpose and has a distinct lifecycle that defines how the component is created and destroyed.

2.5.1 Activities

An activity represents a single screen with a user interface. For example, an email application might have one activity that shows a list of new emails, another activity to compose an email, and another activity for reading emails. Although the activities work together to form a cohesive user experience in the email application, each one is independent of the others. As such, a different application can start any one of these activities (if the email application allows it). For example, a camera application can start

18 the activity in the email application that composes new mail, in order for the user to share a picture.

An activity is implemented as a subclass of Activity and you can learn more about it in the Activities developer guide.

2.5.2 Services

A service is a component that runs in the background to perform long-running operations or to perform work for remote processes. A service does not provide a user interface. For example, a service might play music in the background while the user is in a different application, or it might fetch data over the network without blocking user interaction with an activity. Another component, such as an activity, can start the service and let it run or bind to it in order to interact with it.

A service is implemented as a subclass of Service.

2.5.3 Content providers

A content provider manages a shared set of application data. You can store the data in the , an SQLite database, on the web, or any other persistent storage location your application can access. Through the content provider, other applications can query or even modify the data (if the content provider allows it). For example, the Android system provides a content provider that manages the user's contact information. As such, any

19 application with the proper permissions can query part of the content provider (such as

ContactsContract.Data) to read and write information about a particular person.

Content providers are also useful for reading and writing data that is private to your application and not shared. For example, the Note Pad sample application uses a content provider to save notes.

A content provider is implemented as a subclass of ContentProvider and must implement a standard set of APIs that enable other applications to perform transactions. For more information, see the Content Providers developer guide.

2.5.4 Broadcast receivers

A broadcast receiver is a component that responds to system-wide broadcast announcements. Many broadcasts originate from the system—for example, a broadcast announcing that the screen has turned off, the battery is low, or a picture was captured.

Applications can also initiate broadcasts—for example, to let other applications know that some data has been downloaded to the device and is available for them to use.

Although broadcast receivers don't display a user interface, they may create a status bar notification to alert the user when a broadcast event occurs. More commonly, though, a broadcast receiver is just a "gateway" to other components and is intended to do a very minimal amount of work. For instance, it might initiate a service to perform some work based on the event.

20

A broadcast receiver is implemented as a subclass of BroadcastReceiver and each broadcast is delivered as an Intent object. For more information, see the

BroadcastReceiver class.

21

Chapter 3

ARCHITECTURE AND TECHNOLOGY

Chapter 1 and Chapter 2 provided background information about Media player app. This chapter provides detailed information about architecture and design of the Media player app.

3.1 Basic Architecture of Media Player app

As mentioned in Chapter 2, Media player app is designed for Android phones. Like any cloud computing application, Media player app uses client-server model. Figure 4 shows the basic architecture of the Media player app along with cloud storage. As shown in the figure, cloud based Media player consists of:

 Application: User interacts with cloud based Media player using the application.

Application is responsible for accepting user inputs and reacting to user’s input.

Application interacts with Androind OS via the Android APIs.

 Android APIs: Media player app interacts with Android phone OS using

Android APIs. Please refer to section 4.2 for more information about Android

APIs.

 Android OS: The application will use Android APIs to interact with the OS. OS

will then control the hardware to communicate with the cloud.

 Cloud: Cloud is the medium that will forward the request from client to the server

that is connected to the cloud.

22

 Linux OS: On the server side, incoming messages will be forwarded to the OS in

the Pogoplug controller box.

 The OS will forward the requests to the HTTP server.

 HTTP Server: HTTP server is crucial to making overall data transfer work.

HTTP server will resolve the incoming message and forward them the storage that

is connected to Pogoplug box.

CLIENT SERVER

APPLICATION POGOPLUG APIs

ANDROID APIs HTTP SERVER

ANDROID OS LINUX OS

Cloud

Figure 4: Architecture of Cloud Media player app

3.2 Features

Section 1.2 discussed that features supported by Cloud Media app are:

23

 File browsing

 Image Viewer

 Audio Playback

 Video Playback

 Photo Slide Show

 E-Radio

 File upload

Also, as discussed in section 3.1, Cloud Media app needs to communicate with Pogoplug to access the media files.

3.3 Application

Section 2.4 provided information about Android application. As explained in section 2.4, an android application consists of activities, services, content providers, and broadcast receivers. A typical app may or may not use all these components. Cloud Media player app mostly consists of activities. Activities are classes that must extend the Activity base class and must implement onCreate method. Figure 5 shows various activities required for Cloud Media player app. Figure 5 also shows how various activities interact with each other in the application.

24

LoginScreenActivity

RadioScreenActivity UserScreenActivity SlideShowActivity

FileUploaderActivity FileScreenActivity

ImageViewerActivity AudioPlayerActivity VideoPlayerActivity

Figure 5: Control flow in Cloud Media player app

As shown in the figure, LoginScreenActivity is the class that is instantiated when the application starts. When user login is successful, LoginScreenActivity will start

UserScreenActivity. UserScreenActivity will display the main screen. Next, based on user input UserScreenActivity will start any one of FileScreenActivity,

FileUploaderActivity, VideoPlayerActivity, AudioPlayerActivity, ImageViewerActivity,

RadioPlayerActivity, and SlideShowActivity. Each of these activities will present their own screens to the user and take appropriate actions. More details about each of the activity classes are provided in section 4.3.

25

Chapter 4

IMPLEMENTATION DETAILS

This chapter discusses the implementation details such as Android API used, APIs used to interact with the cloud, and structure in which the application is developed.

4.1 Media cloud

The Pogoplug device is the cloud that stores all the media files and the application uses

Pogoplug APIs to interact with the cloud. Pogoplug supports APIs using standard HTTP

GET/PUT commands. The main features provided by the cloud are the storage of the media files and easy and structured access to this stored data.

The structured Pogoplug APIs provide object oriented API access to different object classes within the system [13]. Major classes in the APIs are

1. User

This object represents all the details of the user. These details include the user id,

screen name, primary email address, list of registered email addresses for the user

and a field containing the details if the email id is validated or not.

2. Service

This object contains device id that owns the service, service id, service class, type

of access to this service, user’s name for the service, version string of the service,

api url to use when using the service, on line status.

26

3. Device

Device object consists of details such as device id, device name, version string,

flags about the device, user id of the owner, list of services representing services

on this device and user object representing the owner of this device.

4. File

File object represents the file stored on the cloud. It consists of file id, namespace

id, parent id (file id of the parent), user id of the owner that owns this file, file

type, name, mime type of the primary stream attached to this file, file size,

creation date of the file, modification date, thumbnail and preview. Thumbnail

and preview are the file ids of the extra stream that represents thumbnail and

preview of the file respectively. General file types are 0-Normal file, 1-Directory,

2-Extra stream and 3-Symbolic link.

The main Pogoplug APIs [13] used for implementing are given in the table below:

27

METHOD INPUT OUTPUT DESCRIPTION loginUser Email id, Validation token, Authenticates a user by email and

Password user object password and returns a validation

token. listServices: Validation Sequence of Lists all the services available to a

Token, service objects, user exposed by a specific device

device Id searchFiles: Validation Page offset, Search an entire service based on

token, Count, sequence some criteria.

search of file objects

criteria listFiles: Validation Page offset, List the contents of some

token, Count, sequence directory, namespace, or service in

device Id, of file objects a paginated fashion.

service Id createFile Validation File object Creates a new child file or

token, directory inside a parent directory.

device Id, The newly created file will be

service Id, empty, and data can be written to

file name using the data stream API.

Table 4: Pogoplug APIs

28

4.2 Android APIs

Section 3.1 described high level architecture of the Cloud Media player app. Various classes described in section 3.1 have to interact with Android platform in order to do things like displaying content on the screen, accepting user input, playing audio/video etc. This is achieved using Android APIs [14].

The Android platform provides a framework API that applications can use to interact with the underlying Android system. The framework API consists of:

 A core set of packages and classes

 A set of XML elements and attributes for declaring a manifest file

 A set of XML elements and attributes for declaring and accessing resources

 A set of Intents

 A set of permissions that applications can request, as well as permission

enforcements included in the system

29

API Method Input Output Description setContentView Layout None Sets view to indicated

layout getIntent None intent Returns intent

Intent.getStringExtra None Argument Returns argument

String string findViewById widget Widget ID Returns widget ID for

specified widget

MediaPlayer.setDataSource URL None Sets specified URL as

media data source

MediaPlayer.prepare None None Prepare data source

for media streaming startActivity Activity None Start specified activity

JSONArray.getJSONObject String JSONObject Get JSONObject that

matches the specified

string

BitmapFactory.decode URI Bitmap Decode image file

specified by URI and

return bitmap

Table 5: Android APIs

30

4.3 Android client

The main features provided by the Media Cloud App are streaming the audio and video files from the cloud, displaying the images stored on the cloud, slideshow of the stored images, and e-radio. The app also uses file management for all these files. The main functionalities of the android client are as given below:

1. Provide an UI for the user to log in to access files on the cloud.

2. User interface for showing the files and folders stored on the cloud.

3. Music player for playing audio files and for radio

4. Image viewer for playing the slide show and for displaying the image files

5. Video player for streaming video files

6. UI for uploading the files from the android device to the cloud

4.3.1 Login Screen

Source Files: LoginScreenActivity.java, login.xml

The screenshot in Figure 6 shows the user interface for log in. User needs to provide an email id and password to access the storage. The Pogoplug API loginUser is used to authenticate the user. The user has access to all the stored files once he signs in the application. Appropriate error messages are given in case the log in is unsuccessful.

31

Figure 6: Login Screen

4.3.2 Main Screen

Source Files: UserScreenActivity.java, userscreen.xml

Once the user login is successful, main screen of Cloud Media app is presented to the user. Figure 7 shows the main screen of Cloud Media app. As shown, this figure allows user to select one of various functions supported by the app, such as image viewer, audio player etc. Appropriate handlers are called to take action depending on the user selection.

The Pogoplug API ―listServices‖ is used before main screen is presented to the user.

32

Figure 7: Main Screen

4.3.3 File View

Source Files: FileScreenActivity.java, filescreen.xml

Figure 8 shows the file and directory listing. This screen is displayed when user selects

File Viewer in the main screen. Appropriate Activities are called to take action depending on the user selection. The Pogoplug API listServices and listFiles are mainly used to show the files/directory listing.

33

Figure 8: File view

4.3.4 Music player

Source Files: AudioPlayerActivity.java, RadioScreenActivity.java, audioplayer.xml, radio.xml

Figure 9 shows the audio/radio player for playing the music files. To play audio, the user can access the Music folder and select the file to play. Alternatively, user can click on

Radio and songs from the Music folder will be played in a random order.

34

The player has different controls such as pause, next track, previous track, shuffle, repeat, stop etc. In case of Radio only stop, pause and next track buttons are provided.

(A) (B)

Figure 9: (A) - Audio player screen, (B) – Radio player screen

4.3.5 Image Viewer

Source Files: ImageViewerActivity.java, SlideShowActivity.java, imageviewer.xml, slideshow.xml

Figure 10 is the screen shot for the image viewer. To view the images user can select from Image folder or Slide show option. If the user choose to use the image folder, he/she needs to select each file manually, whereas in slide show mode, all the images are

35 displayed at small interval. The images are scaled before displaying, to fit the android device.

(A) (B)

Figure 10: (A) - Image diaglog box, (B) – Loaded image

4.3.6 Video player

Source Files: VideoPlayerActivity.java, videoplayer.xml

Android API has video view control to enable video streaming. Path of the video file is set and media controller is set for this videoview. Video streaming starts once this video view is brought into focus.

36

4.3.7 File Uploading

Source Files: FileUploaderActivity.java, fileuploader.xml

The user has the ability to upload file from the android device to the cloud. This functionality makes use of Pogoplug API createFile to achieve the goal. A dialog box is used to indicate file upload progress.

Figure 11: File uploading

37

Chapter 5

PERFORMANCE EVALUATION

The main advantage of Media Cloud app is in the ease of use with which users can access data stored in cloud. As discussed in Chapter 2, performance of any cloud computing system is characterized by [9, 16]:

1. Consistency: Ability of a computer-related hardware or software component

to consistently perform according to its specifications

2. Availability: Ability of the system to perform work when it is expected to

perform work

3. Partition Tolerance: Ability of the system to perform in the event of arbitrary

message loss or failure of part of the system

4. Response Time: Time taken to complete requested operation

Media streaming is highly sensitive to response time, resulting in noticeable glitches, interruptions during playback if response time is longer than can be tolerated. Response time is a function of network connection speed, which itself is dependent upon the connection technology and Radio signal strength. Following data was collected to evaluate performance of the Media Cloud app.

As shown in the table 6, good connection speed of at least 3G or better is required to provide good quality audio/video playback. Thus, we can conclude that personal media cloud application exhibits good consistency and availability as long as high speed internet connectivity (better than 3G speeds) is guaranteed.

38

CONNECTION BW LIMIT MEDIA OBSERVATION

EDGE 237 Kb/s Audio/Video Jittery audio, no video

3G 384 Kb/s Audio Good quality MP3 playback

3G 384Kb/s Video SD Minimal interruptions

3G 384Kb/s Video HD Jittery video

4G 100Mb/s Audio/Video Good quality Audio/Video

Wi-Fi (G) 54Mb/s Audio/Video Good quality Audio/Video

WiFi (N) 150Mb/s Audio/Video Good quality Audio/Video

Table 6: Media Cloud app performance evaluation

Other aspect of performance is usability. Being a personal cloud, this system does not face the issues associated with multi-user commercial cloud systems such as limited space, recurring costs, limited content etc.

39

Chapter 6

CONCLUSION AND FUTURE WORK

The personal media cloud player application provides a low cost solution for personal media cloud. Moreover, the cost is not related to storage capacity and does not require any monthly expenses, unlike commercial media clouds such as iCloud and Amazon cloud.

The app provides simple user interface and features like video streaming, photo slideshow, e-Radio, file upload etc. that are not found in many of the cloud applications available.

Based on performance studies we conclude that the personal media cloud application exhibits good consistency and availability characteristics as long as high speed internet connectivity (better than 3G speeds) is avaialble.

6.1 Future work

6.1.1 Playlist Management

This feature will allow users to specify playlist of media files to be played.

6.1.2 File Sharing

Users will specify email IDs to share the files with and the app will setup the share.

40

6.1.3 Folder sync up

User will specify the folders that need to be sync’ed up with cloud. User will also specify how frequently the folders should be sync’ed up. Based on this information, the app will periodically sync folders with the cloud.

41

APPENDIX

Source Code

******************************** AudioPlayerActivity.java ******************************** package com.android.cloudplayer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import com.android.cloudplayer.ImageViewerActivity.BGThread; import com.android.cloudplayer.ImageViewerActivity.MyRunnable; import android.R.drawable; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.ImageView; /** * * @author Prajakta Sarurkar * This activity creates an UI for audio playback on the files. */ public class AudioPlayerActivity extends Activity { private static MediaPlayer mp; private String devID, svcID, mediaType; private String valToken, userID; private String fileReq; private boolean pauseAction = false;

42 private static boolean playAction = false; private boolean shuffleAction = false; private boolean repeatAction = false; private boolean filesDone = true; private String [] fileIDArry; private String [] fileNameArry; private int fileIndex; private int fileNum; private int fileCnt = 0; private Handler handler; private Thread audioThread; private ProgressDialog prgDialog;

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.audioplayer); Intent i = getIntent();

userID = i.getStringExtra("userID"); valToken = i.getStringExtra("valToken"); devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); fileIndex = i.getIntExtra("fileIndex", 0); fileNum = i.getIntExtra("fileNum", 1); fileIDArry = new String[fileNum]; fileNameArry = new String[fileNum]; fileIDArry = i.getStringArrayExtra("fileID"); fileNameArry = i.getStringArrayExtra("fileName");

Log.i("AudioPlayer", "Entry"); Log.i("AudioPlayer", "userID "+userID); Log.i("AudioPlayer", "valToken "+valToken); Log.i("AudioPlayer", "devID "+devID); Log.i("AudioPlayer", "svcID "+svcID); Log.i("AudioPlayer", "fileID "+fileIDArry[0]); Log.i("AudioPlayer", "fileNum "+fileNum); Log.i("AudioPlayer", "fileIndex "+fileIndex);

Button btnPlay = (Button) findViewById(R.id.btnPlay); Button btnStop = (Button) findViewById(R.id.btnStop); Button btnPause = (Button) findViewById(R.id.btnPause); Button btnNext = (Button) findViewById(R.id.btnNext); Button btnPrev = (Button) findViewById(R.id.btnPrev); Button btnRepeat = (Button) findViewById(R.id.btnRepeat); Button btnShuffle = (Button) findViewById(R.id.btnShuffle);

43

if (playAction) { mp.stop(); mp.release(); playAction = false; } if (fileNum == 1) filesDone = true; mp = new MediaPlayer(); Log.i("playAudio", "fileIndex " + fileIndex + "Length " + fileIDArry.length); Log.i("playAudio", "fileID " + fileIDArry[fileIndex]);

Log.i("AudioPlayer", "To play Audio"); // Create a handler to update the UI handler = new Handler();

audioThread = new BGThread(); audioThread.start(); Log.i("Audio Thread ", audioThread.toString()); if (audioThread != null && audioThread.isAlive()) { prgDialog = ProgressDialog.show(this, "Audio Player", "Loading audio"); }

//playAudio();

mp.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if (filesDone) { mp.release(); playAction = false; finish(); } else { getNextPlayIndex(); playAudio(); } } });

btnNext.setOnTouchListener(new OnTouchListener ()

44

{ @Override public boolean onTouch(View v, MotionEvent event) { Log.i("NextB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN && playAction) { getNextIndex(); playAudio(); } return true; } });

btnPrev.setOnTouchListener(new OnTouchListener () {

@Override public boolean onTouch(View v, MotionEvent event) { Log.i("PrevB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN && playAction) { getPrevIndex(); playAudio(); } return true; } });

btnRepeat.setOnTouchListener(new OnTouchListener () { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("RepeatB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN && playAction) { repeatAction = !repeatAction; if (repeatAction) { filesDone = false; Log.i("Changing color ", "Magenta"); // btnRepeat.setEnabled(true); } // else // btnRepeat.setEnabled(false); } return true; }

45

}); btnShuffle.setOnTouchListener(new OnTouchListener () { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("ShuffleB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN && playAction) { shuffleAction = !shuffleAction; } return true; } }); btnPause.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("PauseB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN && playAction) { pauseAction = !pauseAction; if (pauseAction) mp.pause(); else mp.start(); } return true; } }); btnStop.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("StopB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN && playAction) { mp.release(); playAction = false; finish(); } return true; } }); btnPlay.setOnTouchListener(new OnTouchListener()

46

{ @Override public boolean onTouch(View v, MotionEvent event) { Log.i("PlayB", "playAction "+playAction); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (!playAction) { mp = new MediaPlayer(); playAudio(); } else if (playAction & pauseAction) { mp.start(); pauseAction = false; } } return true; } }); }

/** * Start streaming Audio file from requested location */ private void playAudio () { Log.i("playAudio", "fileIndex " + fileIndex + "Length "); Log.i("playAudio", "fileID " + fileIDArry[fileIndex]);

try { mp.reset(); mp.setDataSource("http://service.pogoplug.com/svc/files/"+valToken+"/"+devID+ "/"+svcID+"/"+fileIDArry[fileIndex]+"/strm"); mp.prepare(); mp.start(); playAction = true; } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e)

47

{ e.printStackTrace(); }

}

/** * Get Previous file */ private void getPrevIndex () { if (fileNum > 1) { if (shuffleAction) fileIndex = (((int) (Math.random()*1000)) % fileNum); else fileIndex = (fileIndex - 1) % fileNum; } }

/** * Get Next file */ private void getNextPlayIndex () { if (fileNum > 1) { if (shuffleAction) fileIndex = (((int) (Math.random()*1000)) % fileNum); else fileIndex = (fileIndex + 1) % fileNum;

}

if (!repeatAction) fileCnt ++;

if (fileCnt == fileNum) filesDone = true; } private void getNextIndex () { if (fileNum > 1) { if (shuffleAction) fileIndex = (((int) (Math.random()*1000)) % fileNum); else fileIndex = (fileIndex + 1) % fileNum; }

48

}

/** * Thread for diaglog */ public class BGThread extends Thread { @Override public void run() {

playAudio(); handler.post(new MyRunnable());

} }

public class MyRunnable implements Runnable { public void run() { //imageView.setImageBitmap(imgBitmap); prgDialog.dismiss(); } }

}

******************************** FileScreenActivity.java ******************************** package com.android.cloudplayer; import org.json.JSONArray; import android.app.Activity; import android.os.Bundle; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException;

49 import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.ListActivity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.ArrayAdapter; import android.widget.Toast;

/** * * @author Prajakta Sarurkar * This activity creates an UI for displaying all the directories and files. * Appropriate action is taken in case the user clicks on a directory or file * depending on the type of the file. */ public class FileScreenActivity extends Activity { //private JSONArray svcArr; private String devID, svcID, parentID, sortCrit; private String valToken, userID; private JSONArray fileArr; private String fileReq; private SimpleAdapter adapter; private ListView fileListView; private ArrayList > fileList; private static String searchCrit; private String [] fileID; private String [] fileName; private int fileSize;

/** Called when the activity is first created. */ @Override

50

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState); setContentView(R.layout.filescreen);

TextView txtUserID = (TextView) findViewById(R.id.txtUserID); Intent i = getIntent(); userID = i.getStringExtra("userID"); Log.i("User ID in FileScreen", userID); txtUserID.setText(userID);

valToken = i.getStringExtra("valToken"); devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); parentID = i.getStringExtra("parentID"); sortCrit = i.getStringExtra("sortcrit"); searchCrit = i.getStringExtra("searchCrit");

try { if(!searchCrit.equals("")) fileReq = "http://service.pogoplug.com/svc/api/json/searchFiles?searchcrit=mediatype+=+" +searchCrit+ "&valtoken="+valToken+"&serviceid="+svcID + "&deviceid="+devID; else if(parentID.equals("")) fileReq = "http://service.pogoplug.com/svc/api/json/listFiles?sortcrit=" +sortCrit+ "&valtoken="+valToken+"&deviceid="+devID+"&serviceid="+svcID; else fileReq = "http://service.pogoplug.com/svc/api/json/listFiles?sortcrit=" +sortCrit+ "&valtoken="+valToken+"&deviceid="+devID+"&serviceid="+svcID +"&sortcrit=+type&parentid="+parentID; Log.i("fileReq", fileReq); String fileResp = getHTTPResponse(fileReq); Log.i("fileResp", fileResp.toString()); JSONObject fileObj = new JSONObject (fileResp); Log.i("Back from buildData", "BuildData"); fileArr = fileObj.optJSONArray("files");

fileList = buildData(); Log.i("Back from buildData","size "+fileList.size());

fileListView = (ListView) findViewById(R.id.listView1); String[] from = { "fileName", "fileType" }; int[] to = { android.R.id.text1, android.R.id.text2 };

adapter = new SimpleAdapter(this, fileList, android.R.layout.simple_list_item_2, from, to); fileListView.setAdapter(adapter);

51

fileListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int pos, long id) { try { JSONObject jObj = fileArr.getJSONObject(pos); String parentID; if (jObj.getString("type").equals("1")) { parentID = jObj.getString("fileid"); fileReq = "http://service.pogoplug.com/svc/api/json/listFiles?sortcrit=" +sortCrit+

"&valtoken="+valToken+"&deviceid="+devID+"&serviceid="+svcID

+"&sortcrit=+type&parentid="+parentID; Log.i("fileReq", fileReq); String fileResp = getHTTPResponse(fileReq); Log.i("fileResp", fileResp.toString()); JSONObject fileObj = new JSONObject (fileResp); clrData(fileArr.length()); adapter.notifyDataSetChanged(); //Log.i("Back from buildData", "BuildData"); fileArr = fileObj.optJSONArray("files"); updateData(); adapter.notifyDataSetChanged(); } else if (jObj.getString("type").equals("0")) { fileID = new String[fileArr.length()]; fileName = new String[fileArr.length()]; int fileIndex = 0; int fileNum = 1; fileID[0] = jObj.getString("fileid"); fileName[0] = jObj.getString("filename"); fileSize = jObj.getInt("size");

Log.i("Mime Type", jObj.getString("mimetype")); if (jObj.getString("mimetype").equals("audio/mpeg")) { if (searchCrit.equals("audio")) { fileNum = fileArr.length(); Log.i("toAudio", "Crit equals Audio");

52

for (int index = 0;index < fileNum;index ++) { fileID[index] = fileArr.getJSONObject(index).getString("fileid"); fileName[index] = fileArr.getJSONObject(index).getString("filename");

if (fileID[index].equals(jObj.getString("fileid"))) fileIndex = index; } } else { Log.i("toAudio", "Crit not equals Audio"); fileID[0] = jObj.getString("fileid"); //fileIndex = 0; } Log.i("FileChk", "Selected "+jObj.getString("filename")); Log.i("FileChk", "Launching audio player"); Intent audioScreen = new Intent(getApplicationContext(), AudioPlayerActivity.class); //Sending data to another Activity audioScreen.putExtra("userID", userID); audioScreen.putExtra("valToken", valToken); audioScreen.putExtra("devID", devID); audioScreen.putExtra("svcID", svcID); audioScreen.putExtra("fileID", fileID); audioScreen.putExtra("fileName", fileName); audioScreen.putExtra("fileNum", fileNum); audioScreen.putExtra("fileIndex", fileIndex);

startActivity(audioScreen); } else if (jObj.getString("mimetype").equals("video/mp4")) { Intent videoScreen = new Intent(getApplicationContext(), VideoPlayerActivity.class); //Sending data to another Activity videoScreen.putExtra("userID", userID); videoScreen.putExtra("valToken", valToken); videoScreen.putExtra("devID", devID); videoScreen.putExtra("svcID", svcID); videoScreen.putExtra("fileID", fileID);

53

videoScreen.putExtra("fileName", fileName); videoScreen.putExtra("fileNum", fileNum); videoScreen.putExtra("fileIndex", fileIndex);

startActivity(videoScreen);

} else if ((jObj.getString("mimetype").equals("image/jpeg")) || (jObj.getString("mimetype").equals("image/png")) || (jObj.getString("mimetype").equals("image/bmp"))) { Intent photoScreen = new Intent(getApplicationContext(), ImageViewerActivity.class); photoScreen.putExtra("valToken", valToken); photoScreen.putExtra("devID", devID); photoScreen.putExtra("svcID", svcID); photoScreen.putExtra("fileID", fileID[0]); photoScreen.putExtra("fileName", fileName[0]); photoScreen.putExtra("fileSize", fileSize); Log.i("fileScreen", "start ImageViewer"); startActivity(photoScreen); } } } catch(Exception ex) { ex.printStackTrace(); } } } );

} catch (Exception e) { e.printStackTrace(); } }

private void clrData(int length) throws JSONException { if(fileArr != null) { Log.i("Inside clrData", Integer.toString(fileArr.length())); String [] fileNameArr = new String[fileArr.length()]; String [] fileType = new String [fileArr.length()];

54

String fType; for (int index = 0;index < length;index ++) { fileNameArr[index] = ""; fileType[index] = ""; fileList.set(index, putData("", "")); } } }

private void updateData() throws JSONException {

if(fileArr != null) { Log.i("Inside updateData", Integer.toString(fileArr.length())); String [] fileNameArr = new String[fileArr.length()]; String [] fileType = new String [fileArr.length()]; String fType; for (int index = 0;index < fileArr.length();index ++) { fileNameArr[index] = fileArr.getJSONObject(index).getString("filename"); fType = fileArr.getJSONObject(index).getString("type"); Log.i("fType", fType); if (fType.equals("0")) { fileType[index] = fileArr.getJSONObject(index).getString("mimetype"); } else if (fType.equals("1")) fileType[index] = "Directory"; { } Log.i("fileType", fileType[index]); fileList.set(index, putData(fileNameArr[index],fileType[index])); //list.add(putData(fileNameArr[index],fileType[index]));

} } else fileList.set(0, putData("No files to display", ""));

Log.i("file List", fileList.toString());

}

/** * * @return ArrayList File List

55

* @throws JSONException */

private ArrayList> buildData() throws JSONException { ArrayList> list = new ArrayList>(); if(fileArr != null) { String [] fileNameArr = new String[fileArr.length()]; String [] fileType = new String [fileArr.length()]; String fType; for (int index = 0;index < fileArr.length();index ++) { fileNameArr[index] = fileArr.getJSONObject(index).getString("filename"); fType = fileArr.getJSONObject(index).getString("type"); Log.i("fType", fType); if (fType.equals("0")) { fileType[index] = fileArr.getJSONObject(index).getString("mimetype"); } else if (fType.equals("1")) fileType[index] = "Directory"; { } Log.i("fileType", fileType[index]); list.add(putData(fileNameArr[index],fileType[index]));

} } else list.add(putData("No files to display", "")); return list; }

/** * * @param String name * @param String type * @return HashMap of the files with key value pair of File name and File type */

private HashMap putData(String name, String type) { HashMap item = new HashMap(); item.put("fileName", name); item.put("fileType", type); return item; }

56

/** * * @param String HTTP Request * @return String HTTP Response */

@SuppressWarnings("finally") private String getHTTPResponse (String httpReq) { String httpResponse = null; HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(httpReq); try { Log.i("In HTTP response", httpReq); HttpResponse response = client.execute(httpGet); Log.i("response", response.toString()); StatusLine statusLine = response.getStatusLine(); Log.i("In HTTP response", statusLine.toString());

int statusCode = statusLine.getStatusCode(); Log.i("In HTTP response", String.valueOf(statusCode)); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); Log.i("Content", content.toString()); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); httpResponse = reader.readLine(); } else { Log.i("parseJSON", "Failed to download file"); } } catch (ClientProtocolException e) { Log.i("ProtocolException", "In protocol Catch"); Toast.makeText(this, "Protocol Error", Toast.LENGTH_LONG).show(); //e.printStackTrace(); } catch (IOException e) { Log.i("IOException", "In IO Catch"); Toast.makeText(this, "Connection Error", Toast.LENGTH_LONG).show(); //e.printStackTrace(); } finally {

57

Log.i("Response Return", httpResponse); client.getConnectionManager().shutdown(); return httpResponse; } }

@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.fileoptions, menu);

return true; }

@Override public boolean onOptionsItemSelected(MenuItem item) {

int id = item.getItemId(); boolean changeFlag = false;

switch (id) { case R.id.name: if (sortCrit.equals("-name")) sortCrit = "+name"; else sortCrit = "-name"; changeFlag = true; break;

case R.id.type: if (sortCrit.equals("-type")) sortCrit = "+type"; else sortCrit = "-type"; changeFlag = true; break;

case R.id.date: if (sortCrit.equals("-date")) sortCrit = "+date"; else sortCrit = "-date"; changeFlag = true; break;

case R.id.size: if (sortCrit.equals("-size"))

58

sortCrit = "+size"; else sortCrit = "-size"; changeFlag = true; break; } if (changeFlag) { Toast.makeText(this, sortCrit.toString(), Toast.LENGTH_SHORT).show();

try { fileReq = "http://service.pogoplug.com/svc/api/json/listFiles?sortcrit=" +sortCrit+ "&valtoken="+valToken+"&deviceid="+devID+"&serviceid="+svcID +"&sortcrit=+type&parentid="+parentID; Log.i("fileReq", fileReq); String fileResp = getHTTPResponse(fileReq); Log.i("fileResp", fileResp.toString()); JSONObject fileObj = new JSONObject (fileResp); Log.i("Back from buildData", "BuildData"); fileArr = fileObj.optJSONArray("files");

updateData();

adapter.notifyDataSetChanged(); } catch(Exception ex) { ex.printStackTrace(); } } return true; }

}

******************************** ImageViewerActivity.java ******************************** package com.android.cloudplayer; import java.io.IOException; import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.entity.BufferedHttpEntity;

59 import org.apache.http.impl.client.DefaultHttpClient; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.widget.ImageView; import android.widget.TextView; /** * * @author Prajakta Sarurkar * This activity creates an UI for displaying Images */ public class ImageViewerActivity extends Activity { private String devID; private String svcID; private String valToken; private String fileID; private String fileName; private int fileSize, scaling = 1; private ProgressDialog prgDialog; private ImageView imageView; private Handler handler; private Bitmap imgBitmap; private Thread imgThread;

@Override public void onCreate(Bundle savedInstanceState) { Intent i = getIntent(); valToken = i.getStringExtra("valToken"); devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); fileID = i.getStringExtra("fileID"); fileName = i.getStringExtra("fileName"); fileSize = i.getIntExtra("fileSize", 0)*10;

super.onCreate(savedInstanceState); setContentView(R.layout.imageviewer); TextView txt = (TextView) findViewById(R.id.textView1); txt.setText(fileName);

// Create a handler to update the UI

60

handler = new Handler(); // get the latest imageView after restart of the application imageView = (ImageView) findViewById(R.id.imageView1);

imgThread = new BGThread(); imgThread.start(); Log.i("Image Thread ", imgThread.toString()); if (imgThread != null && imgThread.isAlive()) { prgDialog = ProgressDialog.show(this, "Image Viewer", "Loading image"); } }

// Save the thread @Override public Object onRetainNonConfigurationInstance() { return imgThread; }

// dismiss dialog if activity is destroyed @Override protected void onDestroy() { if (prgDialog != null && prgDialog.isShowing()) { prgDialog.dismiss(); prgDialog = null; } super.onDestroy(); }

// Utiliy method to download image from the cloud private Bitmap getBitmap() throws IOException { int refSize = 4*1024*1024; scaling = ((int) fileSize/refSize) * 2; if (scaling == 0) scaling = 1;

Log.i("ImageViewer", "File Size is " + Integer.toString(fileSize) + " Scaling is " + Integer.toString(scaling));

//scaling = 1; Log.i(" Scaling is ", Integer.toString(scaling)); //ImageView bmImage = (ImageView)findViewById(R.id.imageView1); BitmapFactory.Options bmOptions; bmOptions = new BitmapFactory.Options(); bmOptions.inSampleSize = scaling; bmOptions.inPurgeable = true; bmOptions.inInputShareable = true;

61

String imageURL = "http://service.pogoplug.com/svc/files/"+valToken+"/"+devID+ "/"+svcID+"/"+fileID+"/strm";

Log.i("fileReq", imageURL); Bitmap bitmap = null;

HttpGet httpRequest = new HttpGet(imageURL); HttpClient httpClient = new DefaultHttpClient(); HttpResponse response = null; try { response = (HttpResponse) httpClient.execute(httpRequest); HttpEntity entity = response.getEntity(); BufferedHttpEntity bufferedHttpEntity = new BufferedHttpEntity(entity); InputStream is = bufferedHttpEntity.getContent(); bitmap = BitmapFactory.decodeStream(is, null, bmOptions); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bitmap; }

/** * Thread for diaglog */ public class BGThread extends Thread { @Override public void run() { try { imgBitmap = getBitmap(); handler.post(new MyRunnable()); } catch (IOException e) { e.printStackTrace(); } finally {

} } }

62

public class MyRunnable implements Runnable { public void run() { imageView.setImageBitmap(imgBitmap); prgDialog.dismiss(); } }

}

******************************** LoginScreenActivity.java ******************************** package com.android.cloudplayer;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.HttpHostConnectException; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONObject; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast;

/** * @author Prajakta Sarurkar * This activity accomplishes the user login and displays appropriate messages in case of errors. */ public class LoginScreenActivity extends Activity {

private EditText userId; private EditText password;

63

private String valToken; private String userID; private JSONObject user;

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.login); }

/** * * @param view * LoginHandler is invoked when clicked on the Sign In button. * It forms a login request using the loginuser API, and takes an appropriate action * depending on the HTTP response. */ public void loginHandler(View view) { try { userId = (EditText) findViewById(R.id.editText1); password = (EditText) findViewById(R.id.editText2);

String emailId = userId.getText().toString().trim();

if (!(android.util.Patterns.EMAIL_ADDRESS.matcher(emailId).matches())) Toast.makeText(this, "Please enter valid email address", Toast.LENGTH_LONG).show();

String pwd = password.getText().toString().trim(); String loginReq = "http://service.pogoplug.com/svc/api/loginUser?email="+emailId+"&password="+pwd;

Log.i("Request URL", loginReq);

String loginResp = getHTTPResponse(loginReq); if (loginResp != null) { try { Log.i("JSON", "instantiate json" + loginResp); JSONObject jsonObj = new JSONObject(loginResp); Log.i("JSON", "Value is" + jsonObj.toString()); Log.i("JSON", "Names are" + jsonObj.names().toString()); if (jsonObj.has("valtoken")) valToken = jsonObj.getString("valtoken"); if (jsonObj.has("user"))

64

user = jsonObj.optJSONObject("user"); if(user.has("screenname")) userID = user.getString("screenname");

Log.i("User", "ValToken" + valToken); Log.i("User", "User" + user.names().toString());

// Added to change the screen Intent userScreen = new Intent(getApplicationContext(), UserScreenActivity.class);

//Sending data to another Activity userScreen.putExtra("userID", userID); userScreen.putExtra("valToken", valToken); startActivity(userScreen); } catch (Exception e) { e.printStackTrace(); } } else { Log.i("JSON", "No HTTP Response"); } } catch(Exception ex) { Log.i("Inside Catch ", ex.toString()); Toast.makeText(this, "Unable to Login", Toast.LENGTH_LONG).show(); } }

/** * * @param view * CancelHandler is invoked when clicked on the Cancel button. */

public void cancelHandler(View view) { //close the application finish(); }

/** * * @param String HTTP Request * @return String HTTP Response

65

* */

private String getHTTPResponse (String httpReq) { String httpResponse = null; HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(httpReq); Log.i("loginHandler","getHTTPResponse()" ); try { Log.i("loginHandler","Inside try" ); HttpResponse response = client.execute(httpGet); Log.i("loginHandler","after calling execute" ); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); Log.i("In HTTP response", String.valueOf(statusCode)); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); httpResponse = reader.readLine(); } else { Toast.makeText(this, "Incorrect login or password", Toast.LENGTH_LONG).show(); Log.i("parseJSON", "Failed to download file"); } } catch (ClientProtocolException e) { Log.i("ProtocolException", "In protocol Catch"); Toast.makeText(this, "Protocol Error", Toast.LENGTH_LONG).show(); } catch (IOException e) { Log.i("IOException", "In IO Catch"); Toast.makeText(this, "Connection Error", Toast.LENGTH_LONG).show(); } finally { client.getConnectionManager().shutdown(); return httpResponse;

} }

}

66

******************************** RadioScreenActivity.java ******************************** package com.android.cloudplayer; import org.json.JSONArray; import android.app.Activity; import android.app.ProgressDialog; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.Bundle; import android.os.Handler; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONObject; import com.android.cloudplayer.AudioPlayerActivity.BGThread; import com.android.cloudplayer.AudioPlayerActivity.MyRunnable; import android.content.Intent; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.TextView;

/** * @author Prajakta Sarurkar * This activity is used for e-Radio screen */ public class RadioScreenActivity extends Activity { private String devID, svcID, searchCrit; private String valToken; private JSONArray fileArr; private String fileReq; private static MediaPlayer mp;

67

private boolean pauseAction = false; private static boolean playAction = false; private int fileIndex, fileNum; private String [] fileIDArry; private String [] fileNameArry; private TextView txtFileName; private Handler handler; private Thread audioThread; private ProgressDialog prgDialog;

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.radio);

txtFileName = (TextView) findViewById(R.id.txtFileName);

Button btnPause = (Button) findViewById(R.id.btnRadPause); Button btnNext = (Button) findViewById(R.id.btnRadNext); Log.i("txtFileName", txtFileName.toString()); Button btnStop = (Button) findViewById(R.id.btnRadStop); Log.i("btnNext", "printing btnNext"); Log.i("btnNext", btnNext.toString());

Intent i = getIntent();

valToken = i.getStringExtra("valToken"); devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); searchCrit = i.getStringExtra("searchCrit");

Log.i("Radio", "here"); try { fileReq = "http://service.pogoplug.com/svc/api/json/searchFiles?searchcrit=mediatype+=+" +searchCrit+ "&valtoken="+valToken+"&serviceid="+svcID + "&deviceid="+devID;

Log.i("fileReq", fileReq); String fileResp = getHTTPResponse(fileReq); Log.i("fileResp", fileResp.toString()); JSONObject fileObj = new JSONObject (fileResp); Log.i("Back from buildData", "BuildData"); fileArr = fileObj.optJSONArray("files");

fileIDArry = new String[fileArr.length()];

68

fileNameArry = new String[fileArr.length()]; fileNum = fileArr.length();

for (int index = 0;index < fileNum;index ++) { fileIDArry[index] = fileArr.getJSONObject(index).getString("fileid"); fileNameArry[index] = fileArr.getJSONObject(index).getString("filename"); } Log.i("FileChk", "Launching audio player");

} catch (Exception e) { e.printStackTrace(); }

if (!playAction) { mp = new MediaPlayer(); getNextIndex(); // playAudio(); // playAction = true; }

handler = new Handler();

audioThread = new BGThread(); audioThread.start(); Log.i("Audio Thread ", audioThread.toString()); if (audioThread != null && audioThread.isAlive()) { prgDialog = ProgressDialog.show(this, "Audio Player", "Loading audio"); }

mp.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { getNextIndex(); playAudio(); } });

btnNext.setOnTouchListener(new OnTouchListener () { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("NextB", "playAction ");

69

if (event.getAction() == MotionEvent.ACTION_DOWN) { getNextIndex(); playAudio(); } return true; } });

btnPause.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("PauseB", "playAction "); if (event.getAction() == MotionEvent.ACTION_DOWN) { pauseAction = !pauseAction; if (pauseAction) mp.pause(); else mp.start(); } return true; } });

btnStop.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("StopB", "playAction "); if (event.getAction() == MotionEvent.ACTION_DOWN) { playAction = false; mp.release(); finish(); } return true; } }); }

/** * Play requested file */ private void playAudio () { Log.i("In playAudio", "fileIndex " + fileIndex + "Length ");

70

Log.i("In playAudio", "fileID " + fileIDArry[fileIndex]);

try { txtFileName.setText(" "); txtFileName.setText(fileNameArry[fileIndex]); mp.reset();

mp.setDataSource("http://service.pogoplug.com/svc/files/"+valToken+"/"+devID+ "/"+svcID+"/"+fileIDArry[fileIndex]+"/strm"); mp.prepare(); mp.start(); Log.i("Returning from PlayAudio", "Return"); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }

private void getNextIndex () { fileIndex = (((int) (Math.random()*10000)) % fileNum); }

@SuppressWarnings("finally") private String getHTTPResponse (String httpReq) { String httpResponse = null; HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(httpReq); try { Log.i("In HTTP response", httpReq); HttpResponse response = client.execute(httpGet); Log.i("response", response.toString()); StatusLine statusLine = response.getStatusLine(); Log.i("In HTTP response", statusLine.toString());

int statusCode = statusLine.getStatusCode(); Log.i("In HTTP response", String.valueOf(statusCode)); if (statusCode == 200)

71

{ HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); Log.i("Content", content.toString()); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); httpResponse = reader.readLine(); } else { Log.i("parseJSON", "Failed to download file"); } } catch (ClientProtocolException e) { Log.i("ProtocolException", "In protocol Catch"); e.printStackTrace(); } catch (IOException e) { Log.i("IOException", "In IO Catch"); e.printStackTrace(); } finally { Log.i("Response Return", httpResponse); client.getConnectionManager().shutdown(); return httpResponse; } }

/** * Thread for dialog */ public class BGThread extends Thread { @Override public void run() {

playAudio(); handler.post(new MyRunnable());

} }

public class MyRunnable implements Runnable { public void run() { //imageView.setImageBitmap(imgBitmap); prgDialog.dismiss(); }

72

}

}

******************************** SlideShowActivity.java ******************************** package com.android.cloudplayer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONObject; import com.android.cloudplayer.ImageViewerActivity.BGThread; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView;

/** * @author Prajakta Sarurkar * This activity is used for Slide Show screen */ public class SlideShowActivity extends Activity { private static String devID, searchCrit; private static String svcID; private static String valToken; private static String fileID;

73

private static String fileName; private String fileReq; private JSONArray fileArr; private static String [] fileIDArry; private String [] fileNameArry; private static int [] fileSizeArry; private static int fileNum; private static int fileSize, scaling = 1; private static ProgressDialog prgDialog; private static ImageView imageView; private static Handler handler; private static Bitmap imgBitmap; private BGThread imgThread = null;

@Override public void onCreate(Bundle savedInstanceState) { Intent i = getIntent(); valToken = i.getStringExtra("valToken"); devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); searchCrit = i.getStringExtra("searchCrit");

super.onCreate(savedInstanceState); setContentView(R.layout.slideshow); TextView txt = (TextView) findViewById(R.id.textView1); txt.setText(fileName);

Log.i("Inside Slide ShowActivity", "SlideShowActivity"); // Create a handler to update the UI handler = new Handler(); // get the latest imageView after restart of the application imageView = (ImageView) findViewById(R.id.imageView1);

try { fileReq = "http://service.pogoplug.com/svc/api/json/searchFiles?searchcrit=mediatype+=+" +searchCrit+ "&valtoken="+valToken+"&serviceid="+svcID + "&deviceid="+devID;

Log.i("fileReq", fileReq); String fileResp = getHTTPResponse(fileReq); Log.i("fileResp", fileResp.toString()); JSONObject fileObj = new JSONObject (fileResp);

fileArr = fileObj.optJSONArray("files");

fileIDArry = new String[fileArr.length()]; fileNameArry = new String[fileArr.length()];

74

fileSizeArry = new int[fileArr.length()]; fileNum = fileArr.length(); Log.i("Back from buildData", Integer.toString(fileNum)); for (int index = 0;index < fileNum;index ++) { fileIDArry[index] = fileArr.getJSONObject(index).getString("fileid"); fileNameArry[index] = fileArr.getJSONObject(index).getString("filename"); fileSizeArry[index] = fileArr.getJSONObject(index).getInt("size"); } Log.i("FileChk", "Launching slide show player");

} catch (Exception e) { e.printStackTrace(); }

if (imgBitmap != null) { imageView.setImageBitmap(imgBitmap); } // Check if the thread is already running // imgThread = (Thread) getLastNonConfigurationInstance(); if(imgThread == null) { startSlideShow(); imgThread.classPtr = this; Log.i("Slide Show", "Back from Thread 11111"); }

}

// Save the thread public void myFinish () { finish(); }

@Override public Object onRetainNonConfigurationInstance() { return imgThread; }

// dismiss dialog if activity is destroyed @Override protected void onDestroy() {

75

if (prgDialog != null && prgDialog.isShowing()) { prgDialog.dismiss(); prgDialog = null; } super.onDestroy(); }

public void startSlideShow() { Log.i("Inside Activity", "Start SlideShow"); prgDialog = ProgressDialog.show(this, "Slide Show", "Loading"); imgThread = new BGThread(); imgThread.start(); }

// Utiliy method to download image from the cloud private static Bitmap getBitmap(int index) throws IOException { int refSize = 4*1024*1024; fileSize = fileSizeArry[index] * 10; fileID = fileIDArry[index]; scaling = ((int) fileSize/refSize) * 2; if (scaling == 0) scaling = 1;

Log.i("ImageViewer", "Ref Size " + refSize + "File Size is " + Integer.toString(fileSize) + " Scaling is " + Integer.toString(scaling));

BitmapFactory.Options bmOptions; bmOptions = new BitmapFactory.Options(); bmOptions.inSampleSize = scaling; bmOptions.inPurgeable = true; bmOptions.inInputShareable = true; String imageURL = "http://service.pogoplug.com/svc/files/"+valToken+"/"+devID+ "/"+svcID+"/"+fileID+"/strm";

Log.i("fileReq", imageURL); Bitmap bitmap = null;

HttpGet httpRequest = new HttpGet(imageURL); HttpClient httpClient = new DefaultHttpClient(); HttpResponse response = null; try { response = (HttpResponse) httpClient.execute(httpRequest); HttpEntity entity = response.getEntity(); BufferedHttpEntity bufferedHttpEntity = new BufferedHttpEntity(entity); InputStream is = bufferedHttpEntity.getContent(); bitmap = BitmapFactory.decodeStream(is, null, bmOptions); } catch (ClientProtocolException e)

76

{ // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } httpClient.getConnectionManager().shutdown(); return bitmap; }

public class BGThread extends Thread { public SlideShowActivity classPtr; @Override public void run() { try { for (int index = 0;index < fileNum;index ++) { Log.i("Inside thread run", "Index is " + Integer.toString(index)); imgBitmap = getBitmap(index); Log.i("Inside thread run", "Back from getBitmap");

// imageView.setImageBitmap(imgBitmap); Log.i("Inside thread run", "set Bitmap");

handler.post(new MyRunnable()); } try { Log.i("Slide Show Thread", "Before Sleeping"); sleep(3000); classPtr.myFinish();

// getLock(); // notify(); } catch(InterruptedException e) { e.printStackTrace(); }

} catch (IOException e) { e.printStackTrace();

77

} finally {

} } }

public static class MyRunnable implements Runnable { public void run() { imageView.setImageBitmap(imgBitmap); prgDialog.dismiss(); } }

private String getHTTPResponse (String httpReq) { String httpResponse = null; HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(httpReq); try { Log.i("In HTTP response", httpReq); HttpResponse response = client.execute(httpGet); Log.i("response", response.toString()); StatusLine statusLine = response.getStatusLine(); Log.i("In HTTP response", statusLine.toString());

int statusCode = statusLine.getStatusCode(); Log.i("In HTTP response", String.valueOf(statusCode)); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); Log.i("Content", content.toString()); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); httpResponse = reader.readLine(); } else { Log.i("parseJSON", "Failed to download file"); } } catch (ClientProtocolException e) { Log.i("ProtocolException", "In protocol Catch"); e.printStackTrace(); } catch (IOException e) {

78

Log.i("IOException", "In IO Catch"); e.printStackTrace(); }

finally { Log.i("Response Return", httpResponse); client.getConnectionManager().shutdown(); return httpResponse; } }

}

******************************** UserScreenActivity.java ******************************** package com.android.cloudplayer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONObject; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast;

/** * @author Prajakta Sarurkar * This activity is invoked after successful login to the application and the UI displays * all the available media folders */

79

public class UserScreenActivity extends Activity { private JSONArray svcArr; private String devID, svcID; private String valToken, userID;

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState); setContentView(R.layout.userscreen);

TextView txtUserID = (TextView) findViewById(R.id.txtUserID);

Intent i = getIntent(); userID = i.getStringExtra("userID"); txtUserID.setText(userID);

valToken = i.getStringExtra("valToken"); try { String svcReq = "http://service.pogoplug.com/svc/api/json/listServices?valtoken="+valToken; Log.i("svcReq", svcReq); String svcResp = getHTTPResponse(svcReq); if (svcResp != null) { Log.i("svcResp", svcResp.toString()); JSONObject svcResponseObj = new JSONObject(svcResp); Log.i("Services", svcResponseObj.names().toString());

svcArr = svcResponseObj.optJSONArray("services"); devID = svcArr.getJSONObject(0).getString("deviceid"); svcID = svcArr.getJSONObject(0).getString("serviceid"); Log.i("Device", devID); Log.i("Service", svcID);

} else { Log.i("Server Error", "svcID null"); } } catch (Exception e) { e.printStackTrace();

80

}

}

/** * * @param view * Handler to start the next activity on click of Files button */ public void fileHandler(View view) { // Added to change the screen Intent fileScreen = new Intent(getApplicationContext(), FileScreenActivity.class);

//Sending data to another Activity fileScreen.putExtra("userID", userID); fileScreen.putExtra("valToken", valToken); fileScreen.putExtra("devID", devID); fileScreen.putExtra("svcID", svcID); fileScreen.putExtra("parentID",""); fileScreen.putExtra("sortcrit", "-type"); fileScreen.putExtra("searchCrit","" ); startActivity(fileScreen);

}

/** * * @param view * Handler to start the next activity on click of Music button */ public void audioHandler(View view) { // Added to change the screen Intent audioScreen = new Intent(getApplicationContext(), FileScreenActivity.class);

//Sending data to another Activity audioScreen.putExtra("userID", userID); audioScreen.putExtra("valToken", valToken); audioScreen.putExtra("devID", devID); audioScreen.putExtra("svcID", svcID); audioScreen.putExtra("parentID",""); audioScreen.putExtra("sortcrit", "-type"); audioScreen.putExtra("searchCrit","audio" ); startActivity(audioScreen); }

/** *

81

* @param view * Handler to start the next activity on click of Movies button */ public void videoHandler(View view) { // Added to change the screen Intent videoScreen = new Intent(getApplicationContext(), FileScreenActivity.class);

//Sending data to another Activity videoScreen.putExtra("userID", userID); videoScreen.putExtra("valToken", valToken); videoScreen.putExtra("devID", devID); videoScreen.putExtra("svcID", svcID); videoScreen.putExtra("parentID",""); videoScreen.putExtra("sortcrit", "-type"); videoScreen.putExtra("searchCrit","video" ); startActivity(videoScreen);

}

/** * * @param view * Handler to start the next activity on click of Radio button */ public void radioHandler(View view) { // Added to change the screen Intent radioScreen = new Intent(getApplicationContext(), RadioScreenActivity.class);

//Sending data to another Activity Log.i("Start Activity", "Radio"); radioScreen.putExtra("valToken", valToken); radioScreen.putExtra("devID", devID); radioScreen.putExtra("svcID", svcID); radioScreen.putExtra("searchCrit","audio" ); startActivity(radioScreen);

}

/** * * @param view * Handler to start the next activity on click of Images button */ public void imageHandler(View view) { // Added to change the screen

82

Intent imageScreen = new Intent(getApplicationContext(), FileScreenActivity.class);

//Sending data to another Activity imageScreen.putExtra("userID", userID); imageScreen.putExtra("valToken", valToken); imageScreen.putExtra("devID", devID); imageScreen.putExtra("svcID", svcID); imageScreen.putExtra("parentID",""); imageScreen.putExtra("sortcrit", "-type"); imageScreen.putExtra("searchCrit","image" ); startActivity(imageScreen);

}

/** * * @param view * Handler to start the next activity on click of Slide Show button */ public void slideShowHandler(View view) { // Added to change the screen Intent showScreen = new Intent(getApplicationContext(), SlideShowActivity.class);

//Sending data to another Activity showScreen.putExtra("userID", userID); showScreen.putExtra("valToken", valToken); showScreen.putExtra("devID", devID); showScreen.putExtra("svcID", svcID); showScreen.putExtra("searchCrit","image" ); startActivity(showScreen);

}

/** * * @param String HTTP Request * @return String HTTP Response */ private String getHTTPResponse (String httpReq) { String httpResponse = null; HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(httpReq); try { Log.i("In HTTP response", httpReq); HttpResponse response = client.execute(httpGet); Log.i("response", response.toString());

83

StatusLine statusLine = response.getStatusLine(); Log.i("In HTTP response", statusLine.toString());

int statusCode = statusLine.getStatusCode(); Log.i("In HTTP response", String.valueOf(statusCode)); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); Log.i("Content", content.toString()); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); httpResponse = reader.readLine(); } else { Log.i("parseJSON", "Failed to download file"); } } catch (ClientProtocolException e) { Log.i("ProtocolException", "In protocol Catch"); Toast.makeText(this, "Protocol Error", Toast.LENGTH_LONG).show(); } catch (IOException e) { Log.i("IOException", "In IO Catch"); Toast.makeText(this, "Connection Error", Toast.LENGTH_LONG).show(); }

finally { Log.i("Response Return", httpResponse); client.getConnectionManager().shutdown(); return httpResponse; } }

}

******************************** VideoPlayerActivity.java ******************************** package com.android.cloudplayer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity;

84 import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import com.android.cloudplayer.AudioPlayerActivity.BGThread; import com.android.cloudplayer.AudioPlayerActivity.MyRunnable; import android.R.drawable; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Color; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnInfoListener; import android.media.MediaPlayer.OnPreparedListener; import android.media.MediaPlayer.OnVideoSizeChangedListener; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.View; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.MediaController; import android.widget.VideoView;

/** * @author Prajakta Sarurkar * This activity is invoked for video playback */ public class VideoPlayerActivity extends Activity { private VideoView vView; private String devID, svcID; private String valToken, userID; private String path = ""; private String [] fileIDArry; private String [] fileNameArry; private int fileIndex; private int fileNum;

85 private Handler handler; private Thread videoThread; private ProgressDialog prgDialog;

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.videoplayer); Intent i = getIntent();

userID = i.getStringExtra("userID"); valToken = i.getStringExtra("valToken"); devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); fileIndex = i.getIntExtra("fileIndex", 0); fileNum = i.getIntExtra("fileNum", 1); fileIDArry = new String[fileNum]; fileNameArry = new String[fileNum]; fileIDArry = i.getStringArrayExtra("fileID"); fileNameArry = i.getStringArrayExtra("fileName");

Log.i("VideoPlayer", "Entry"); Log.i("VideoPlayer", "userID "+userID); Log.i("VideoPlayer", "valToken "+valToken); Log.i("VideoPlayer", "devID "+devID); Log.i("VideoPlayer", "svcID "+svcID); Log.i("VideoPlayer", "fileID "+fileIDArry[0]); Log.i("VideoPlayer", "fileNum "+fileNum); Log.i("VideoPlayer", "fileIndex "+fileIndex);

vView = (VideoView) findViewById(R.id.videoView1);

playVideo(); } /** * This function is used for playing back requested video file * */ private void playVideo() { path = "http://service.pogoplug.com/svc/files/"+valToken+"/"+devID+ "/"+svcID+"/"+fileIDArry[fileIndex]+"/strm"; Uri video = Uri.parse(path); vView.setVideoURI(video); //vView.setVideoPath(path); vView.setMediaController(new MediaController(this)); vView.start(); vView.requestFocus();

86

}

public class BGThread extends Thread { @Override public void run() {

playVideo(); handler.post(new MyRunnable());

} }

public class MyRunnable implements Runnable { public void run() { prgDialog.dismiss(); } } } ******************************** FileUploaderActivity.java ******************************** package com.android.cloudplayer; import java.io.BufferedReader; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject;

87

import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener;

/** * @author Prajakta Sarurkar * This activity creates an UI for uploading files from device to the cloud. */ public class FileUploaderActivity extends Activity { private String devID, svcID, valToken, userID; private ListView fileListView; private ArrayList > fileList; private SimpleAdapter adapter; private File [] fList; private String [] fileNameArr; private String [] fileType; private String [] fileMimeType; private String fileReq; private String fileId, parentId; private ProgressDialog prgDialog; private Handler handler; private Thread fileThread; private String filePath; private String dirMusic, dirPhoto,dirVideo, dirMisc; private File path; private String fileName; private String fType; private File fileToUpload;

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fileuploader);

Intent i = getIntent(); valToken = i.getStringExtra("valToken");

88

devID = i.getStringExtra("devID"); svcID = i.getStringExtra("svcID"); userID = i.getStringExtra("userID");

filePath = "/sdcard"; path = new File(filePath); fileList = loadFileList(path); fileListView = (ListView) findViewById(R.id.listView1); String[] from = { "fileName", "fileType" }; int[] to = { android.R.id.text1, android.R.id.text2 };

adapter = new SimpleAdapter(this, fileList, android.R.layout.simple_list_item_2, from, to); fileListView.setAdapter(adapter);

getUploadDirectory();

fileListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int pos, long id) { try { fileName = fileNameArr[pos]; fType = fileType[pos]; fileToUpload = fList[pos];

if(fType.equals("Directory")) { filePath += "/" + fileName; Log.i("new Path ", filePath); clrData(fList.length); adapter.notifyDataSetChanged(); path = new File(filePath); updateFileList(path); adapter.notifyDataSetChanged(); } else {

// Create a handler to update the UI handler = new Handler(); fileThread = new BGThread(); fileThread.start(); Log.i("File Thread ", fileThread.toString()); if (fileThread != null && fileThread.isAlive()) { prgDialog = ProgressDialog.show(view.getContext(), "File Uploader", "Uploading " + fileName);

89

} } } catch(Exception ex) { ex.printStackTrace(); } } } ); }

// dismiss dialog if activity is destroyed @Override protected void onDestroy() { if (prgDialog != null && prgDialog.isShowing()) { prgDialog.dismiss(); prgDialog = null; } super.onDestroy(); } /** * * @return ArrayList File List */

private ArrayList> loadFileList(File path) { ArrayList> list = new ArrayList>();

Log.i("Path", path.toString()); if(path.exists()) { fList = path.listFiles(filter); Log.i("no of Files", Integer.toString(fList.length)); fileNameArr = new String[fList.length]; fileType = new String [fList.length]; fileMimeType = new String[fList.length]; String []fType;

for (int index = 0; index < fList.length; index++) { fileNameArr[index] = fList[index].getName(); if (fList[index].isDirectory()) fileType[index] = "Directory"; else if (fList[index].isFile()) { if(fileNameArr[index].contains("."))

90

{ fType = fileNameArr[index].split("\\."); Log.i("file Name", fType[1]); fileMimeType[index] = fType[fType.length-1]; if(fileMimeType[index].equalsIgnoreCase("jpg")) fileType[index] = "image/jpeg"; else if(fileMimeType[index].equalsIgnoreCase("mp3") || fileMimeType[index].equalsIgnoreCase("amr")) fileType[index] = "audio/mpeg"; else if(fileMimeType[index].equalsIgnoreCase("mp4") || fileMimeType[index].equalsIgnoreCase("3gp")) fileType[index] = "video/mp4"; else { fileType[index] = "File"; } } else fileType[index] = "File";

} Log.i("file Name + Mime ", fileNameArr[index] + " " + fileMimeType[index]); list.add(putData(fileNameArr[index],fileType[index])); } } else list.add(putData("No files to display", "")); return list; }

FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String filename) { File sel = new File(dir, filename); // Filters based on whether the file is hidden or not return (sel.isFile() || sel.isDirectory()) && !sel.isHidden(); } };

private void clrData(int length) throws JSONException { if(fList != null) { Log.i("Inside clrData", Integer.toString(fList.length)); String [] fileNameArr = new String[fList.length]; String [] fileType = new String [fList.length];

91

for (int index = 0;index < length;index ++) { fileNameArr[index] = ""; fileType[index] = ""; fileList.set(index, putData("", "")); } } }

private void updateFileList(File path) {

Log.i("Path", path.toString()); if(path.exists()) { fList = path.listFiles(filter); Log.i("no of Files", Integer.toString(fList.length)); fileNameArr = new String[fList.length]; fileType = new String [fList.length]; String [] fType;

if(fList.length > 0) { for (int index = 0; index < fList.length; index++) { fileNameArr[index] = fList[index].getName(); if (fList[index].isDirectory()) fileType[index] = "Directory"; else if (fList[index].isFile()) { if(fileNameArr[index].contains(".")) { fType = fileNameArr[index].split("\\."); Log.i("file Name", fType[1]); fileMimeType[index] = fType[fType.length- 1];

if(fileMimeType[index].equalsIgnoreCase("jpg")) fileType[index] = "image/jpeg"; else if(fileMimeType[index].equalsIgnoreCase("mp3") || fileMimeType[index].equalsIgnoreCase("amr")) { fileType[index] = "audio/mpeg"; } else if(fileMimeType[index].equalsIgnoreCase("mp4") || fileMimeType[index].equalsIgnoreCase("3gp")) fileType[index] = "video/mp4"; else fileType[index] = "File";

92

} else fileType[index] = "File"; } Log.i("file Name + List size ", fileNameArr[index] + " " + Integer.toString(fList.length)); fileList.set(index, putData(fileNameArr[index],fileType[index])); } } else { fileList.set(0, putData("No files to display", "")); } } else fileList.set(0, putData("No files to display", "")); }

/** * * @param String name * @param String type * @return HashMap of the files with key value pair of File name and File type */

private HashMap putData(String name, String type) { HashMap item = new HashMap(); item.put("fileName", name); item.put("fileType", type); return item; }

/** * * @param String HTTP Request * @return String HTTP Response */

@SuppressWarnings("finally") private String getHTTPResponse (String httpReq) { String httpResponse = null; HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(httpReq); try { Log.i("In HTTP response", httpReq); HttpResponse response = client.execute(httpGet);

93

Log.i("response", response.toString()); StatusLine statusLine = response.getStatusLine(); Log.i("In HTTP response", statusLine.toString());

int statusCode = statusLine.getStatusCode(); Log.i("In HTTP response", String.valueOf(statusCode)); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); Log.i("Content", content.toString()); BufferedReader reader = new BufferedReader(new InputStreamReader(content)); httpResponse = reader.readLine(); } else { Log.i("parseJSON", "Failed to download file"); } } catch (ClientProtocolException e) { Log.e("ProtocolException", e.toString()); Toast.makeText(this, "Protocol Error", Toast.LENGTH_LONG).show(); } catch (IOException e) { Log.e("IOException", e.toString()); Toast.makeText(this, "Connection Error", Toast.LENGTH_LONG).show(); } finally { Log.i("Response Return", httpResponse); client.getConnectionManager().shutdown(); return httpResponse; } }

private void getUploadDirectory() { dirMusic = ""; dirPhoto = ""; dirVideo = ""; try { String name, type; String dirReq = "http://service.pogoplug.com/svc/api/json/listFiles?valtoken="+valToken+"&deviceid="+devID+"&service id="+svcID; String dirResp = getHTTPResponse(dirReq); Log.i("fileResp", dirResp.toString()); JSONObject fileObj = new JSONObject (dirResp); Log.i("Back from buildData", "BuildData");

94

JSONArray fileArr = fileObj.optJSONArray("files"); for (int index = 0;index < fileArr.length();index ++) { name = fileArr.getJSONObject(index).getString("filename"); type = fileArr.getJSONObject(index).getString("type"); if(name.equalsIgnoreCase("music") && type.equals("1")) { dirMusic = fileArr.getJSONObject(index).getString("fileid"); } else if(name.equalsIgnoreCase("photo") && type.equals("1")) { dirPhoto = fileArr.getJSONObject(index).getString("fileid"); } else if(name.equalsIgnoreCase("video") && type.equals("1")) { dirVideo = fileArr.getJSONObject(index).getString("fileid"); } else if(name.equalsIgnoreCase("misc") && type.equals("1")) { dirMisc = fileArr.getJSONObject(index).getString("fileid"); }

} } catch(Exception ex) { Log.e("Exception in getUploadDir", ex.toString()); } }

private void uploadFile() { try { if(fType.matches("audio/mpeg")) parentId = dirMusic; else if(fType.matches("image/jpeg")) parentId = dirPhoto; else if(fType.matches("video/mp4")) parentId = dirVideo; else parentId = dirMisc;

if(fileName.contains(" ")) { String newFileName = fileName.replace(" ", "_"); fileReq = "http://service.pogoplug.com/svc/api/json/createFile?&valtoken="+valToken+"&deviceid="+devID+"&ser viceid="+svcID

95

+"&filename="+newFileName+"&parentid="+parentId; } else { fileReq = "http://service.pogoplug.com/svc/api/json/createFile?&valtoken="+valToken+"&deviceid="+devID+"&ser viceid="+svcID +"&filename="+fileName+"&parentid="+parentId; }

Log.i("Uploader", "Req " + fileReq);

Log.i("Uploader", "After Req " + fileReq); String fileResp = getHTTPResponse(fileReq); JSONObject fileObj = new JSONObject (fileResp); fileId = fileObj.getJSONObject("file").getString("fileid");

String fileURL = "http://service.pogoplug.com/svc/files/"+valToken+"/"+devID+ "/"+svcID+"/"+fileId+"/strm";

HttpClient http = new DefaultHttpClient(); HttpPut httpRequest = new HttpPut(fileURL); httpRequest.setEntity(new FileEntity(fileToUpload,fType)); HttpResponse response = http.execute(httpRequest);

if (response.getStatusLine().getStatusCode() == 200) { Intent fileScreen = new Intent(getApplicationContext(), FileScreenActivity.class);

//Sending data to another Activity fileScreen.putExtra("userID", userID); fileScreen.putExtra("valToken", valToken); fileScreen.putExtra("devID", devID); fileScreen.putExtra("svcID", svcID); fileScreen.putExtra("parentID",parentId); fileScreen.putExtra("sortcrit", "-type"); fileScreen.putExtra("searchCrit","" ); startActivity(fileScreen);

} } catch(IOException iEx) { Log.e("IOExcption in uploadFile", iEx.toString()); } catch(Exception ex) {

96

Log.e("Excption in uploadFile", ex.toString()); } } /** * Thread for diaglog */ public class BGThread extends Thread { @Override public void run() { try { uploadFile(); handler.post(new MyRunnable()); } catch (Exception ex) { Log.e("Excption in uploadFile", ex.toString()); } } }

public class MyRunnable implements Runnable { public void run() { prgDialog.dismiss(); } }

}

97

BIBLIOGRAPHY

[1] Introduction to Smartphones, [Online]

Available: http://www.pcworld.com/article/246915/the_next_big_things_in_tech.html

[2] Cloud computing with Smartphones, [Online]

Available: http://www.crn.com/news/data-center/232700118/cloud-computing-on- horizon-for-smartphones.htm;jsessionid=3s+dAKuk5iJggkRLBF+M+Q**.ecappj03

[3] Cloud computing and Smartphones, [Online]

Available: http://cloudtimes.org/cloud-computing-and-smartphones/

[4] Gonzalo Huerta-Canepa et al, ―A virtual cloud computing provider for mobile devices‖, Proceeding MCS '10 Proceedings of the 1st ACM Workshop on Mobile Cloud

Computing & Services: Social Networks and Beyond, ACM New York, NY, USA, 2010,

ISBN: 978-1-4503-0155-8

[5] Introduction to Amazon cloud drive, [online]

Available: https://www.amazon.com/clouddrive/learnmore

[6] Introduction to Apple iCloud, [online]

Available: http://www.apple.com/icloud/

[7] Introduction to Zumodrive, [online]

Available: http://www.zumodrive.com/

[8] Barrie Sosinsky, ―Cloud Computing Bible‖, Wiley Publishing, 2011, ISBN: 978-0-

4709-0356-8

98

[9] P. Lougher and D. Shepherd, ―The Design of a Storage Server for Continuous

Media‖, The Computer Journal (1993) 36 (1): 32-42.

[10] Introduction to Pogoplug, [online]

Available: https://pogoplug.com/downloads

[11] Cloud setup using Pogoplug, [online]

Available: http://download.pogoplug.com/meet/setup.html

[12] Pogoplug specifications, [online]

Available: http://download.pogoplug.com/meet/specs.html

[13] Pogoplug API calls, [online]

Available: http://download.pogoplug.com/dev/web.html

[14] Android APIs, [online]

Available: http://developer.android.com/guide/topics/fundamentals.html

[15] Android application components, [online]

Available: http://elinux.org/Android_Architecture

[16] Nancy Lynch and Seth Gilbert, ―Brewer's conjecture and the feasibility of consistent, available, partition-tolerant web services‖, ACM SIGACT News, Volume 33

Issue 2 (2002), pg. 51-59

[17] Definition of personal media cloud, [online]

Available:http://www.pcmag.com/encyclopedia_term/0,2542,t=personal+cloud&i=62784

,00.asp