internal services -...

38
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) 1

Upload: others

Post on 18-Aug-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Internal Services

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

1

Page 2: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Internal Services

• Communication: Email, SMS and telephony

• Audio and video: Record and playback • Sensors: Accelerometer, light, magnetic,

ambient temperature

2

Page 3: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Sending Email: Java

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);}

3

How to send email programmatically: http://www.oodlestechnologies.com/blogs/Send-Mail-in-Android-without-Using-Intent (or search online)

Page 4: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Sending Email: Kotlinfun 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)}

4

Page 5: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent 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);

}

5

Can also use http://developer.android.com/reference/android/telephony/SmsManager.html .You need <uses-permission android:name=”android.permission.SEND_SMS”/>

Page 6: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

SMS: Kotlinfun 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)

}

6

Page 7: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Telephony: Javapublic 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"/>

7

Page 8: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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

}

8

Page 9: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Playing Audio Example: Setup

9

<?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>

1.

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, Kotlin).

Page 10: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

// 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; // . . .@Overridepublic void onClick(View view) {

Activity activity = getActivity();if (activity != null) {

switch (view.getId()) {case R.id.buttonAudioStart:

if (!mStarted) {Intent musicIntent = new Intent(activity, MediaPlaybackService.class);musicIntent.putExtra("URIString", mAudioFileUri.toString());activity.startService(musicIntent); mStarted = true; } break;

case R.id.buttonAudioStop:activity.stopService(new Intent(activity, MediaPlaybackService.class));mStarted = false; break;

case R.id.buttonAudioRecord:startActivityForResult(mRecordAudioIntent, AUDIO_CAPTURED); break;

}}

}public void onActivityResult(int requestCode, int resultCode, Intent data) {

if (resultCode == RESULT_OK && requestCode == AUDIO_CAPTURED) {mAudioFileUri = data.getData(); } }

10

1

2

3

Page 11: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

// AudioFragment.kt

private val mAudioFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).path + File.separator + "sample_audio.mp3"

private lateinit var mAudioFileUri: Uriprivate 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)}

}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {if (resultCode == RESULT_OK && requestCode == AUDIO_CAPTURED) {

if (data != null) {mAudioFileUri = data.data }

}} 11

1

2

3

Page 12: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Media Player States

12Source: https://developer.android.com/reference/android/media/MediaPlayer.html

Page 13: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Playing Audio: Service: Java<service android:enabled="true” android:name=".MediaPlaybackService”/>

// MediaPlayerService.java

public class MediaPlaybackService extends Service {MediaPlayer player;

@Overridepublic IBinder onBind(Intent intent) { return null;}

@Overridepublic void onCreate() {player = MediaPlayer.create(this, R.raw.sample_audio); player.setLooping(true); }

@Overridepublic 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; }

@Overridepublic void onDestroy() { player.stop(); }

}13

Page 14: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Playing Audio: Service: Kotlin<service android:enabled="true” android:name=".MediaPlaybackService”/>

// MediaPlayerService.ktclass MediaPlaybackService : Service() {internal lateinit var player: MediaPlayeroverride 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.extrasif (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) { /* Error handling */ }

return Service.START_STICKY}

override fun onDestroy() { player.stop() }} 14

Page 15: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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>

15

Page 16: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

// VideoFragment.javapublic 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);

@Overridepublic 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).return v;

}}

Handling Video: Java (1)

16

Page 17: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Handling Video: Java (2)

17

// VideoFragment.java (continued)@Overridepublic void onClick(View view) {

switch (view.getId()) {case R.id.buttonVideoStart:

// Load and start the moviemVideoView.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();

}}

}

Page 18: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

// AudioFragment.kt

class VideoFragment : Fragment(), View.OnClickListener {private lateinit var mButtonStart: Buttonprivate lateinit var mButtonStop: Buttonprivate lateinit var mButtonRecord: Buttonprivate lateinit var mVideoView: VideoViewprivate var mVideoFileUri: Uri? = nullprivate 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_videomVideoFileUri = Uri.parse(videoResourceName) }// Guard against no video recorder app (disable the "record" button).

return v}

Handling Video: Kotlin (1)

18

Page 19: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Handling Video: Kotlin (2)override fun onClick(view: View) {

when (view.id) {R.id.buttonVideoStart -> {

// Load and start the moviemVideoView.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

}}

}19

Page 20: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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>

20

Page 21: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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);

@Overridepublic 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);// Set up onClickListener(this) for the buttons

return v;}

21

Page 22: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Handling Images: Java (2)// ImageFragment.java (continued)

@Overridepublic 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:// Finish Activity; call break

}}

22

Page 23: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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);

}}

}

23

Memory management is critical for Bitmaps! Consider using LRU cache, library like 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 )

Page 24: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Handling Images: Kotlin (1)// ImagesFragment.kt

class ImagesFragment : Fragment(), View.OnClickListener {private lateinit var imageView: ImageViewprivate val imageFilePath = Environment.getExternalStoragePublicDirectory(

Environment.DIRECTORY_PICTURES).path + File.separator + "other_image.png"private lateinit var imageBitmap: Bitmapprivate 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)

// Set onClickListener(this) for each Button

return v} /* . . . */ 24

Page 25: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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 SVGsimageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)imageView.setImageResource(R.drawable.ic_scoreboard)

}}R.id.buttonImageCapture -> startActivityForResult(mCaptureImageIntent,

IMAGE_CAPTURED)}

}

25

Page 26: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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?.extrasif (extras != null) {

imageBitmap = extras.get("data") as BitmapimageView.setImageBitmap(imageBitmap)

}}

}

26

Page 27: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Sensors• Uses:

– 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 devices: Moto E (4th gen.), Moto G (5th gen.). See:

http://thewirecutter.com/reviews/best-budget-android-phone, Amazon, eBay

27

Type ExamplesMotion Accelerometer, gyroscopeEnvironmental Light, temperature, humidity, barometric pressureMiscellaneous Camera, microphone, fingerprint, infrared

Page 28: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

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

28

Views

Page 29: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

RecyclerView Workflow

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

Page 30: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Listing Available Sensors: Javaprivate RecyclerView mSensorRecyclerView;

private SensorAdapter mSensorAdapter;

private SensorManager mSensorManager;private List<Sensor> mSensorList;

@Overridepublic 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;} 30

Page 31: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Listing Available Sensors: Kotlinprivate lateinit var mSensorRecyclerView: RecyclerViewprivate lateinit var mAdapter: SensorAdapterprivate lateinit var mSensorManager: SensorManagerprivate 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 SensorManagermSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL)mAdapter = SensorAdapter(mSensorList)mSensorRecyclerView.adapter = mAdaptermSensorRecyclerView.itemAnimator = DefaultItemAnimator()

return v}

31

Page 32: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Sensor HolderJava

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);

}

}

Kotlinprivate inner class SensorHolder(

inflater: LayoutInflater, parent: ViewGroup) : RecyclerView.ViewHolder(

inflater.inflate(R.layout.list_item_sensor, parent, false)) {

private lateinit var mSensor: Sensorprivate lateinit var mDescriptionStr: Stringprivate val mSensorInfoTextView: TextView

init { mSensorInfoTextView = itemView.findViewById(R.id.sensor_data)

}

fun bind(sensor: Sensor) {mSensor = sensormDescriptionStr = getSensorDescription(

sensor)mSensorInfoTextView.text = mDescriptionStr

}}

32

Page 33: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Sensor AdapterJava

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);

}

@Overridepublic void onBindViewHolder(SensorHolder holder,

int position) {Sensor sensor = SensorsFragment.this.mSensorList

.get(position);String sensorDescription = getSensorDescription(

sensor); holder.bind(sensor);}@Overridepublic int getItemCount() {

return SensorList.size(); }}

Kotlinprivate 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 }

}

33

Page 34: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Registering Sensor Updates

Java@Overridepublic void onResume() {

super.onResume(); // . . .// Start listening to sensor updatesfor (Sensor sensor : mSensorList) {

mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);

}}

// . . .@Overridepublic void onPause() {

super.onPause();// Stop updates when pausedmSensorManager.unregisterListener(this);

}

Kotlinoverride fun onResume() {

super.onResume() // . . .// Start listening to sensor updatesfor (sensor in mSensorList) {

mSensorManager.registerListener(this, sensor,SensorManager.SENSOR_DELAY_NORMAL)

}}// . . .override fun onPause() {

super.onPause()// Stop updates when pausedmSensorManager.unregisterListener(this)

}

34

Page 35: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Receiving Sensor Updates

Java@Overridepublic 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);

}

Kotlinoverride 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)

}

35See complete method for how to filter out noise.

Page 36: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Extracting Sensor Parameters

Javapublic String getSensorDescription(

Sensor sensor) {return "Sensor: " + sensor.getName() + "; Ver :" + sensor.getVersion() + "; Range: " + sensor.getMaximumRange() + "; Power: " + sensor.getPower() + "; Res: " + sensor.getResolution();

}

Kotlinfun getSensorDescription(

sensor: Sensor): String {return "Sensor: " + sensor.name + "; Ver :" + sensor.version + "; Range: " + sensor.maximumRange + "; Power: " + sensor.power + "; Res: " + sensor.resolution

}

36

Page 37: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

References• 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 media metadata):

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 37

Page 38: Internal Services - web.cse.ohio-state.eduweb.cse.ohio-state.edu/~champion.17/5236/06_InternalServices.pdf · Sending Email: Java public void sendScoresViaEmail() {Intent emailIntent=

Thank You

Questions and comments?

38