Internal Services CSE 5236: Mobile Application Development

Slides:



Advertisements
Similar presentations
Android Application Development Tutorial. Topics Lecture 4 Overview Overview of Sensors Programming Tutorial 1: Tracking location with GPS and Google.
Advertisements

Chapter 6 Jam! Implementing Audio in Android Apps.
Multimedia.
Programming Mobile Applications with Android September, Albacete, Spain Jesus Martínez-Gómez.
Mobile Programming Lecture 9 Bound Service, Location, Sensors, IntentFilter.
CS378 - Mobile Computing Intents.
1 CMSC 628: Introduction to Mobile Computing Nilanjan Banerjee Introduction to Mobile Computing University of Maryland Baltimore County
CS378 - Mobile Computing Intents. Allow us to use applications and components that are part of Android System – start activities – start services – deliver.
CS378 - Mobile Computing Sensing and Sensors Part 2.
Mobile Device Development Camera and Sensors Dr.YingLiang Ma.
Applications with Multiple Activities. Most applications will have more than one activity. The main activity is started when the application is started.
Intents 1 CS440. Intents  Message passing mechanism  Most common uses:  starting an Activity (open an , contact, etc.)  starting an Activity.
User Interface Layout Interaction. EventsEvent Handlers/Listeners Interacting with a user.
Lecture 2: Android Concepts
CS378 - Mobile Computing Sensing and Sensors Part 2.
Lecture 4: Sensors Topics: Motion, Position, and Environmental Sensors Date: Feb 11, 2016.
Cosc 4735 Activities, fragments, callbacks/listeners/interfaces.
Intents and Broadcast Receivers Dr. David Janzen Except as otherwise noted, the content of this presentation is licensed under the Creative Commons Attribution.
School of Engineering and Information and Communication Technology KIT305/KIT607 Mobile Application Development Android OS –Permissions (cont.), Fragments,
CS371m - Mobile Computing Intents 1. Allow us to use applications and components that are already part of Android System – start activities – start services.
Android Android Sensors Android Sensors: – Accelerometer – Gravity sensor – Linear Acceleration sensor – Magnetic Field sensor – Orientation.
Sensors in Android.
Vijay Kumar Kolagani Dr. Yingcai Xiao
Lecture 4: Sensors Topics: Motion, Position, and Environmental Sensors
Multimedia.
Lecture 2: Android Concepts
CS240: Advanced Programming Concepts
Android Boot Camp for Developers Using Java, 3E
Lecture 4: Sensors Topics: Motion, Position, and Environmental Sensors.
android architecture components with mvvm
Sensors, maps and fragments:
Vijay Kumar Kolagani Dr. Yingcai Xiao
CS499 – Mobile Application Development
Android Introduction Camera.
ANDROID UI – FRAGMENTS UNIT II.
Recap: Android Components
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Developing Android Services
Vijay Kumar Kolagani Dr. Yingcai Xiao
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Many thanks to Jun Bum Lim for his help with this tutorial.
Activities and Intents
Android Programming Tutorial
Lecture 4: Sensors Topics: Motion, Position, and Environmental Sensors.
CIS 470 Mobile App Development
CIS 470 Mobile App Development
Objects First with Java
Mobile Programming Sensors in Android.
Activities and Intents
Lecture 2: Android Concepts
BLP 4216 MOBİL UYGULAMA GELİŞTİRME-2
Objects First with Java
Activities and Fragments
CS 240 – Advanced Programming Concepts
Android Development Tools
Android Application Model I
External Services CSE 5236: Mobile Application Development
User Interface Development
Introduction to Mobile Apps
Android Application Model II
Wrap Up CSE 5236: Mobile Application Development
Android Sensor Programming
CA16R405 - Mobile Application Development (Theory)
External Services CSE 5236: Mobile Application Development
User Interface Development
CIS 694/EEC 693 Android Sensor Programming
Presentation transcript:

Internal Services CSE 5236: Mobile Application Development Instructor: Adam C. Champion, Ph.D. Course Coordinator: Dr. Rajiv Ramnath Reading: Big Nerd Ranch Guide, Chap. 15, 16 (Intents, camera); https://developer.android.com/docs/ (Sensors)

Internal Services Communication: Email, SMS and telephony Audio and video: Record and playback Sensors: Accelerometer, light, magnetic, ambient temperature

Sending Email: Java How to send email programmatically: public void sendScoresViaEmail() { Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.putExtra( android.content.Intent.EXTRA_SUBJECT, "Look at my AWESOME TicTacToe Score!"); // Can also fill To: using putExtra(..., EXTRA_EMAIL) emailIntent.setType("plain/text"); emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, firstPlayerName + " score is " + scorePlayerOne + " and " + secondPlayerName + " score is " + scorePlayerTwo); startActivity(emailIntent); } How to send email programmatically: http://www.oodlestechnologies.com/blogs/Send-Mail-in-Android-without-Using-Intent (or search online)

Sending Email: Kotlin fun sendScoresViaEmail() { val emailIntent = Intent(Intent.ACTION_SEND) emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Look at my AWESOME TicTacToe Score!") emailIntent.type = "plain/text" emailIntent.putExtra(Intent.EXTRA_TEXT, mFirstPlayerName + " score is " + mScorePlayerOne + " and " + mSecondPlayerName + " score is " + mScorePlayerTwo) startActivity(emailIntent) }

SMS: Java public void sendScoresViaSMS() { Intent SMSIntent = new Intent(Intent.ACTION_VIEW); SMSIntent.putExtra("sms_body", "Look at my AWESOME TicTacToe Score!" + firstPlayerName + " score is " + scorePlayerOne + " and " + secondPlayerName + " score is " + scorePlayerTwo); SMSIntent.setType("vnd.android-dir/mms-sms"); startActivity(SMSIntent); } Can also use SMS class; see: http://developer.android.com/reference/android/telephony/SmsManager.html . You need <uses-permission android:name=”android.permission.SEND_SMS”/>

SMS: Kotlin fun sendScoresViaSMS() { val SMSIntent = Intent(Intent.ACTION_VIEW) SMSIntent.putExtra("sms_body", "Look at my AWESOME TicTacToe Score!" + mFirstPlayerName + " score is " + mScorePlayerOne + " and " + mSecondPlayerName + " score is " + mScorePlayerTwo) SMSIntent.type = "vnd.android-dir/mms-sms" startActivity(SMSIntent) }

Telephony: Java Needs: public void callTicTacToeHelp() { Intent phoneIntent = new Intent(Intent.ACTION_DIAL); String phoneNumber = "842-822-4357"; // TIC TAC HELP String uri = "tel:" + phoneNumber.trim(); phoneIntent.setData(Uri.parse(uri)); startActivity(phoneIntent); } Needs: <uses-permission android:name="android.permission.CALL_PHONE"/> Ask why telephony needs permissions. Because phone dials immediately.

Telephony: Kotlin fun callTicTacToeHelp() { val phoneIntent = Intent(Intent.ACTION_DIAL) val phoneNumber = "842-822-4357" // TIC TAC HELP val uri = "tel:" + phoneNumber.trim { it <= ' ' } phoneIntent.data = Uri.parse(uri) startActivity(phoneIntent) }

Playing Audio Example: Setup 1. <?xml version="1.0" encoding="utf-8"?> <LinearLayout ... > <Button ... android:text="Start Audio"/> <Button ... android:text="Stop Audio”/> <Button ... android:text="Record Audio"/> <Button ... android:text="Exit" /> </LinearLayout> 2. View device file system in Android Studio. Transfer files via your computer’s OS (ensure drivers are installed first). Media file is sampleAudio.mp3 in external storage “music directory” (varies among devices). Next slides show AudioFragment code (Java and Kotlin).

// AudioFragment. java private String mAudioFilePath = Environment // AudioFragment.java private String mAudioFilePath = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_MUSIC).getPath() + File.separator + "sample_audio.mp3"; private Intent mRecordAudioIntent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION) private Uri mAudioFileUri; // . . . @Override public void onClick(View view) { Activity activity = getActivity(); if (activity != null) { switch (view.getId()) { case R.id.buttonAudioStart: if (!mStarted) { Intent musicIntent = new Intent(activity.getApplicationContext(), MediaPlaybackService.class); musicIntent.putExtra("URIString", mAudioFileUri.toString()); activity.startService(musicIntent); mStarted = true; } break; case R.id.buttonAudioStop: activity.stopService(new Intent(activity.getApplicationContext(), MediaPlaybackService.class)); mStarted = false; break; case R.id.buttonAudioRecord: startActivityForResult(mRecordAudioIntent, AUDIO_CAPTURED); break; case R.id.buttonAudioExit: activity.finish(); break; } } } public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == AUDIO_CAPTURED) { mAudioFileUri = data.getData(); } } 1 2 3

// AudioFragment. kt private val mAudioFilePath = Environment // AudioFragment.kt private val mAudioFilePath = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_MUSIC).path + File.separator + "sample_audio.mp3" private lateinit var mAudioFileUri: Uri private val mRecordAudioIntent = Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION) override fun onClick(view: View) { when (view.id) { R.id.buttonAudioStart -> if (!mStarted) { val musicIntent = Intent(activity?.applicationContext, MediaPlaybackService::class.java) musicIntent.putExtra("URIString", mAudioFileUri.toString()) activity?.startService(musicIntent) mStarted = true } R.id.buttonAudioStop -> { activity?.stopService(Intent(activity?.applicationContext, MediaPlaybackService::class.java)) mStarted = false } R.id.buttonAudioRecord -> startActivityForResult(mRecordAudioIntent, AUDIO_CAPTURED) R.id.buttonAudioExit -> activity?.finish() } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == RESULT_OK && requestCode == AUDIO_CAPTURED) { if (data != null) { mAudioFileUri = data.data } } } 1 2 3

Media Player States Source: https://developer.android.com/reference/android/media/MediaPlayer.html

Playing Audio: Service: Java <service android:enabled="true” android:name=".MediaPlaybackService”/> // MediaPlayerService.java public class MediaPlaybackService extends Service { MediaPlayer player; @Override public IBinder onBind(Intent intent) { return null;} @Override public void onCreate() { player = MediaPlayer.create(this, R.raw.sample_audio); player.setLooping(true); } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); Bundle extras = intent.getExtras(); if (extras != null) { String audioFileURIString = extras.getString("URIString"); Uri audioFileURI = Uri.parse(audioFileURIString); try { player.reset(); player.setDataSource(this.getApplicationContext(), audioFileURI); player.prepare(); player.start(); } catch (Exception e) { e.printStackTrace(); } } return START_STICKY; } @Override public void onDestroy() { player.stop(); } } Note use of default resource Note need to reset, set and prepare the media player in order to play a new file

Playing Audio: Service: Kotlin <service android:enabled="true” android:name=".MediaPlaybackService”/> // MediaPlayerService.kt class MediaPlaybackService : Service() { internal lateinit var player: MediaPlayer override fun onBind(intent: Intent): IBinder? { return null} override fun onCreate() { player = MediaPlayer.create(this, R.raw.sample_audio) player.apply { isLooping = true } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { super.onStartCommand(intent, flags, startId) val extras = intent.extras if (extras != null) { val audioFileURIString = extras.getString("URIString") val audioFileURI = Uri.parse(audioFileURIString) try { player.reset() player.setDataSource(this.applicationContext, audioFileURI) player.prepare() player.start() } catch (e: Exception) { e.printStackTrace() } } return Service.START_STICKY } override fun onDestroy() { player.stop() } }

Handling Video Using VideoView <?xml version="1.0" encoding="utf-8"?> <LinearLayout ... > <VideoView android:id="@+id/videoView" android:layout_height="175dip" android:layout_width="match_parent" android:layout_gravity="center" /> <Button ... android:text="Start Video"/> <Button ... android:text="Stop Video”/> <Button ... android:text="Record Video"/> <Button ... android:text="Exit" /> </LinearLayout>

Handling Video: Java (1) // VideoFragment.java public class VideoFragment extends Fragment implements View.OnClickListener { private Button mButtonStart, mButtonStop, mButtonRecord; private VideoView mVideoView = null; private Uri mVideoFileUri = null; private Intent mRecordVideoIntent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE); @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Activity activity = getActivity(); View v = inflater.inflate(R.layout.fragment_video, container, false); mVideoView = v.findViewById(R.id.videoView); // Get references to Buttons and for each Button, setOnClickListener(this); String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getPath() + File.separator + "sample_video.mp4"; File videoFile = new File(path); if (videoFile.exists()) { mVideoFileUri = Uri.fromFile(videoFile); } else { // Video file doesn't exist, so load sample video from resources. if (activity != null) { String videoResourceName = "android.resource://" + activity.getPackageName() + File.separator + R.raw.sample_video; mVideoFileUri = Uri.parse(videoResourceName); } } // Guard against no video recorder app (disable the "record" button). if (activity != null) { PackageManager packageManager = activity.getPackageManager(); if (packageManager.resolveActivity(mRecordVideoIntent, PackageManager.MATCH_DEFAULT_ONLY) == null) { buttonRecord.setEnabled(false); } } return v; } }

Handling Video: Java (2) // VideoFragment.java (continued) @Override public void onClick(View view) { switch (view.getId()) { case R.id.buttonVideoStart: // Load and start the movie mVideoView.setVideoURI(mVideoFileUri); mVideoView.start(); break; case R.id.buttonVideoRecord: startActivityForResult(mRecordVideoIntent, VIDEO_CAPTURED); break; case R.id.buttonVideoStop: mVideoView.stopPlayback(); break; case R.id.buttonVideoExit: Activity activity = getActivity(); if (activity != null) { activity.finish(); } break; } } public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == VIDEO_CAPTURED) { mVideoFileUri = data.getData(); } } } Connect startActivityForResult with onActivityResult callback. How does activity know what was the calling activity?

Handling Video: Kotlin (1) // AudioFragment.kt class VideoFragment : Fragment(), View.OnClickListener { private lateinit var mButtonStart: Button private lateinit var mButtonStop: Button private lateinit var mButtonRecord: Button private lateinit var mVideoView: VideoView private var mVideoFileUri: Uri? = null private val mRecordVideoIntent = Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val v = inflater.inflate(R.layout.fragment_audio, container, false) mVideoView = v.findViewById(R.id.videoView) // Get references to Buttons and for each Button, setOnClickListener(this); val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).path + File.separator + "sample_video.mp4" val videoFile = File(path) if (videoFile.exists()) { mVideoFileUri = Uri.fromFile(videoFile) } else { // Video file doesn't exist, so load sample video from resources. val videoResourceName = "android.resource://" + activity?.packageName + File.separator + R.raw.sample_video mVideoFileUri = Uri.parse(videoResourceName) } // Guard against no video recorder app (disable the "record" button). val packageManager = activity?.packageManager if (packageManager?.resolveActivity(mRecordVideoIntent, PackageManager.MATCH_DEFAULT_ONLY) == null) { mButtonRecord.isEnabled = false } return v }

Handling Video: Kotlin (2) override fun onClick(view: View) { when (view.id) { R.id.buttonVideoStart -> { // Load and start the movie mVideoView.setVideoURI(mVideoFileUri) mVideoView.start() } R.id.buttonVideoRecord -> startActivityForResult(mRecordVideoIntent, VIDEO_CAPTURED) R.id.buttonVideoStop -> mVideoView.stopPlayback() R.id.buttonVideoExit -> activity?.finish() } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == RESULT_OK && requestCode == VIDEO_CAPTURED) { if (data != null) { mVideoFileUri = data.data } } }

Handling Images: ImageView <?xml version="1.0" encoding="utf-8"?> <LinearLayout ... > <ImageView android:id="@+id/imageView" android:layout_height="175dip" android:layout_width="match_parent" android:layout_gravity="center" /> <Button ... android:text="Show Image"/> <Button ... android:text="Take Picture"/> <Button ... android:text="Exit" /> </LinearLayout>

Handling Images: Java (1) // ImageFragment.java public class ImagesFragment extends Fragment implements View.OnClickListener { private ImageView imageView = null; private static Uri imageFileURI; private String imageFilePath = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES).getPath() + File.separator + "other_image.png"; private Bitmap imageBitmap = null; private Intent mCaptureImageIntent = new Intent( android.provider.MediaStore.ACTION_IMAGE_CAPTURE); @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_images, container, false); imageView = (ImageView) v.findViewById(R.id.imageView); Button buttonShow = v.findViewById(R.id.buttonImageShow); Button buttonCapture = v.findViewById(R.id.buttonImageCapture); Button buttonExit = v.findViewById(R.id.buttonImageExit); // Set up onClickListener(this) for the buttons return v; } Need to convert the image file into a bitmap.

Handling Images: Java (2) // ImageFragment.java (continued) @Override public void onClick(View view) { switch(view.getId()) { case R.id.buttonImageShow: File imageFile = new File(imageFilePath); if (imageFile.exists()) { imageBitmap = BitmapFactory.decodeFile(imageFilePath); imageView.setImageBitmap(imageBitmap); } else { // File doesn't exist, so load a sample SVG image. imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); imageView.setImageResource(R.drawable.ic_scoreboard); } break; case R.id.buttonImageCapture: startActivityForResult(mCaptureImageIntent, IMAGE_CAPTURED); break; case R.id.buttonImageExit: Activity activity = getActivity(); if (activity != null) { activity.finish(); } break; } }

Handling Images: Java (3) // ImageFragment.java (continued) public void onActivityResult(int requestCode, int resultCode, Intent cameraIntent) { if (resultCode == RESULT_OK && requestCode == IMAGE_CAPTURED) { Bundle extras = cameraIntent.getExtras(); if (extras != null) { imageBitmap = (Bitmap) extras.get("data"); imageView.setImageBitmap(imageBitmap); } } } Explain why the garbage collector is being called Memory management is critical for Bitmaps! Consider using an LRU cache or library such as Glide (https://github.com/bumptech/glide) to handle them. See https://developer.android.com/topic/performance/graphics/index.html for more info. See also: https://issuetracker.google.com/issues/36917456

Handling Images: Kotlin (1) // ImagesFragment.kt class ImagesFragment : Fragment(), View.OnClickListener { private lateinit var imageView: ImageView private val imageFilePath = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES).path + File.separator + "other_image.png" private lateinit var imageBitmap: Bitmap private lateinit var imageFileURI: Uri private val mCaptureImageIntent = Intent( android.provider.MediaStore.ACTION_IMAGE_CAPTURE) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val v = inflater.inflate(R.layout.fragment_images, container, false) imageView = v.findViewById(R.id.imageView) val buttonShow = v.findViewById(R.id.buttonImageShow) val buttonCapture = v.findViewById(R.id.buttonImageCapture) val buttonExit = v.findViewById(R.id.buttonImageExit) // Set onClickListener(this) for each Button return v } // . . .

Handling Images: Kotlin (2) // ImagesFragment.kt (continued) override fun onClick(view: View) { when (view.id) { R.id.buttonImageShow -> { val imageFile = File(imageFilePath) if (imageFile.exists()) { imageBitmap = BitmapFactory.decodeFile(imageFilePath) imageView.setImageBitmap(imageBitmap) } else { // File doesn't exist, so load a sample SVG image. // Disable hardware acceleration for SVGs imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null) imageView.setImageResource(R.drawable.ic_scoreboard) } } R.id.buttonImageCapture -> startActivityForResult(mCaptureImageIntent, IMAGE_CAPTURED) R.id.buttonImageExit -> activity?.finish() } }

Handling Images: Kotlin (3) // ImagesFragment.kt (continued) override fun onActivityResult(requestCode: Int, resultCode: Int, cameraIntent: Intent?) { if (resultCode == RESULT_OK && requestCode == IMAGE_CAPTURED) { val extras = cameraIntent?.extras if (extras != null) { imageBitmap = extras.get("data") as Bitmap imageView.setImageBitmap(imageBitmap) } } }

Sensors Uses: Example Tic-Tac-Toe files: Issues: Provide contextual and environmental data to app Tailor app to environment, how people are using devices Example Tic-Tac-Toe files: SensorsFragment class fragment_sensors.xml, list_item_sensor.xml Issues: Noisy sensor data on real-world devices Best tested on real devices. To simulate sensors on the emulator see: https://github.com/openintents/sensorsimulator Inexpensive real devices: Moto E (4th gen.), Moto G (5th gen.). See: http://thewirecutter.com/reviews/best-budget-android-phone, Amazon, eBay Type Examples Motion Accelerometer, gyroscope Environmental Light, temperature, humidity, barometric pressure Miscellaneous Camera, microphone, fingerprint, infrared

Displaying Sensors Display all device sensors (and their info) in a RecyclerView RecyclerView: displays (possibly large) dynamic list/grid of “items” with limited memory footprint More info: https://developer.android.com/guide/topics/ui/layout/recyclerview.html Views

RecyclerView Workflow Source: Figs. 8.6–8.7, Bill Phillips, Chris Stewart, and Kristin Marsicano, Android Programming: The Big Nerd Ranch Guide, 3rd ed., 2017.

Listing Available Sensors: Java private RecyclerView mSensorRecyclerView; private SensorAdapter mSensorAdapter; private SensorManager mSensorManager; private List<Sensor> mSensorList; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_sensor_list, container, false); Activity activity = getActivity(); RecyclerView sensorRecyclerView = v.findViewById(R.id.sensor_recycler_view); if (activity != null) { sensorRecyclerView.setLayoutManager(new LinearLayoutManager(activity)); mSensorManager = (SensorManager) activity.getSystemService(SENSOR_SERVICE); if (mSensorManager != null) { mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); SensorAdapter adapter = new SensorAdapter(mSensorList); sensorRecyclerView.setAdapter(adapter); sensorRecyclerView.setItemAnimator(new DefaultItemAnimator()); } } return v; }

Listing Available Sensors: Kotlin private lateinit var mSensorRecyclerView: RecyclerView private lateinit var mAdapter: SensorAdapter private lateinit var mSensorManager: SensorManager private lateinit var mSensorList: List<Sensor> private var lastSensorValues = Hashtable<String, FloatArray>() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val v = inflater.inflate(R.layout.fragment_sensor_list, container, false) mSensorRecyclerView = v.findViewById(R.id.sensor_recycler_view) mSensorRecyclerView.layoutManager = LinearLayoutManager(activity) mSensorManager = activity?.getSystemService(SENSOR_SERVICE) as SensorManager mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL) mAdapter = SensorAdapter(mSensorList) mSensorRecyclerView.adapter = mAdapter mSensorRecyclerView.itemAnimator = DefaultItemAnimator() return v }

Sensor Holder Java Kotlin private class SensorHolder extends RecyclerView.ViewHolder { private Sensor mSensor; private String mDescriptionStr; private TextView mSensorInfoTextView; public SensorHolder(LayoutInflater inflater, ViewGroup parent) { super(inflater.inflate( R.layout.list_item_sensor, parent, false)); mSensorInfoTextView = itemView.findViewById(R.id.sensor_data); } public void bind(Sensor sensor) { mSensor = sensor; mDescriptionStr = getSensorDescription( sensor); mSensorInfoTextView.setText( mDescriptionStr); } } private inner class SensorHolder( inflater: LayoutInflater, parent: ViewGroup) : RecyclerView.ViewHolder( inflater.inflate(R.layout.list_item_sensor, parent, false)) { private lateinit var mSensor: Sensor private lateinit var mDescriptionStr: String private val mSensorInfoTextView: TextView init { mSensorInfoTextView = itemView.findViewById(R.id.sensor_data) } fun bind(sensor: Sensor) { mSensor = sensor mDescriptionStr = getSensorDescription( sensor) mSensorInfoTextView.text = mDescriptionStr } }

Sensor Adapter Java Kotlin private class SensorAdapter extends RecyclerView.Adapter<SensorHolder> { private List<Sensor> mSensorList; public SensorAdapter(List<Sensor> sensorList) { mSensorList = sensorList; } @Override public SensorHolder onCreateViewHolder( ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from( getActivity()); return new SensorHolder(inflater, parent); } @Override public void onBindViewHolder(SensorHolder holder, int position) { Sensor sensor = SensorsFragment.this.mSensorList .get(position); String sensorDescription = getSensorDescription( sensor); holder.bind(sensor); } @Override public int getItemCount() { return mSensorList.size(); } } private inner class SensorAdapter( private val mSensorList: List<Sensor>) : RecyclerView.Adapter<SensorHolder>() { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int): SensorHolder { val inflater = LayoutInflater.from( activity) return SensorHolder(inflater, parent) } override fun onBindViewHolder( holder: SensorHolder, position: Int) { val sensor = this@SensorsFragment. mSensorList[position] holder.bind(sensor) } override fun getItemCount(): Int { return mSensorList.size } }

Registering Sensor Updates Java Kotlin @Override public void onResume() { super.onResume(); // . . . // Start listening to sensor updates for (Sensor sensor : mSensorList) { mSensorManager.registerListener( this, sensor, SensorManager.SENSOR_DELAY_NORMAL); } } // . . . @Override public void onPause() { super.onPause(); // Stop updates when paused mSensorManager.unregisterListener(this); } override fun onResume() { super.onResume() // . . . // Start listening to sensor updates for (sensor in mSensorList) { mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL) } } // . . . override fun onPause() { super.onPause() // Stop updates when paused mSensorManager.unregisterListener(this) }

Receiving Sensor Updates Java Kotlin @Override public void onSensorChanged( SensorEvent sensorEvent) { String sensorEventString = sensorEventToString(sensorEvent); // . . . Log.d(TAG, "--- EVENT Raw Values ---\n” + sensorName + "\n" + "Distance Last = >” + distanceOfLastValue + "<\n" + "Distance This = >" + distanceOfThisValue + "<\n" + "Change = >" + change + "<\n" + "Percent = >" + percentageChange + "%\n" + "Last value = " + lastValueString + "<\n" + sensorEventString); } override fun onSensorChanged( sensorEvent: SensorEvent) { val sensorEventString = sensorEventToString(sensorEvent) // . . . Log.d(TAG, "--- EVENT Raw Values ---\n" + sensorName + "\nDistance Last= >" + distanceOfLastValue + "<\n" + "Distance This= >" + distanceOfThisValue + "<\n" + "Change = >" + change + "<\n" + "Percent = >" + percentageChange + "%\n" + "Last value = " + lastValueString + "<\n" + sensorEventString) } See complete method for how to filter out noise.

Extracting Sensor Parameters Java Kotlin public String getSensorDescription( Sensor sensor) { return "Sensor: " + sensor.getName() + "; Ver :" + sensor.getVersion() + "; Range: " + sensor.getMaximumRange() + "; Power: " + sensor.getPower() + "; Res: " + sensor.getResolution(); } fun getSensorDescription( sensor: Sensor): String { return "Sensor: " + sensor.name + "; Ver :" + sensor.version + "; Range: " + sensor.maximumRange + "; Power: " + sensor.power + "; Res: " + sensor.resolution }

References Chapter 11: “Harnessing the Capabilities of your Android Device” from Android SDK 3 Programming for Dummies Chapter 8 from Android Programming: The Big Nerd Ranch Guide, 3rd ed. (RecyclerView) Services: http://developer.android.com/guide/topics/fundamentals/services.html SMS: http://developer.android.com/reference/android/telephony/SmsManager.html SIP (internet telephony): http://developer.android.com/reference/android/net/sip/package-summary.html MediaPlayer: http://developer.android.com/reference/android/media/MediaPlayer.html MediaRecorder: http://developer.android.com/reference/android/media/MediaRecorder.html MediaStore class (extract metadata from media): http://developer.android.com/reference/android/provider/MediaStore.html Camera: http://developer.android.com/reference/android/hardware/Camera.html BitmapFactory: http://developer.android.com/reference/android/graphics/BitmapFactory.html Bitmap: http://developer.android.com/reference/android/graphics/Bitmap.html Sensor: http://developer.android.com/reference/android/hardware/Sensor.html SensorEvent: http://developer.android.com/reference/android/hardware/SensorEventListener.html

Questions and comments? Thank You Questions and comments?