Bazı mobil uygulamalar da insanların koşma, yürüme, bisiklet ya da araba sürme gibi eylemlerini tespit edip, kullanıcıya aktiviteleri hakkında işlevsel bilgiler vermektedir. Örneğin, adım sayar uygulamaları, fitness spor uygulamaları hatta GoogleFit uygulaması dahi bu konu üzerine çalışmaktadır.
Android uygulamalarda, insanların koşma, yürüme, bisiklet ya da araba sürme gibi eylemlerini tespit edebilmek için ActivityRecognitionClient sınıfını kullanmalıyız. Makalemde ise bu konu hakkında Android uygulama yapacağım. Kullanıcı bu aktiviteleri yaparken uygulama arka plan da dahi olsa, kullanıcının yaptığı aktiviteler hakkında bilgi vermeyi sağlayan bir program yazacağım.
Örnek projemizin çıktısı aşağıdaki gibi olacak.
1-Activity Recognition
Android in eski sürümlerinde bu iş için LocationClient, ActivityRecognitionApi. sınıfları kullanılıyordu. Ancak bu sınıflar son zamanlarda kullanımdan kaldırılmıştır. Kullanıcıların eylemlerini tespit etmek için artık ActivityRecognitionClient sınıfı kullanmalıyız. İşte, etkinliği saptamak için kullanılabileceğimiz kod:
1 2 3 4 5 6 7 8 9 10 11 12 |
ActivityRecognitionClient mActivityRecognitionClient = new ActivityRecognitionClient(this); Task<Void> task = mActivityRecognitionClient.requestActivityUpdates( Constants.DETECTION_INTERVAL_IN_MILLISECONDS, mPendingIntent); ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent); ArrayList<DetectedActivity> detectedActivities = (ArrayList) result.getProbableActivities(); for (DetectedActivity activity : detectedActivities) { Log.e(TAG, "Algılanan etkinlik: " + activity.getType() + ", " + activity.getConfidence()); } |
2- Android Proje Oluşturma
Yapmamız gereken adımlar şu şekildedir:
- Android Studio ide’sinde yeni bir proje oluşturalım.
- Android SDK da, SDK Tools sekmesinde bulunan Google Play services APIs‘ini yüklemeliyiz.
- Oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek play-services-location kütüphanesini yüklüyoruz.
12345678build.gradledependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support:appcompat-v7:26.1.0'//...compile 'com.google.android.gms:play-services-location:11.6.0'} - Kullanıcının aktivite değişikliklerini algılayabilmek için belli sürelerde kontrol etmemiz gerekmektedir. Bu zamanı milli saniye cinsinden verip, diğer değişkenleride default değerler vermek için Constant sınıfını tanımlıyoruz.
12345678public class Constants {public static final String BROADCAST_DETECTED_ACTIVITY = "activity_intent";static final long DETECTION_INTERVAL_IN_MILLISECONDS = 30 * 1000;public static final int CONFIDENCE = 70;} - DetectedActivitiesIntentService.java adlı bir sınıf oluşturun. Bu sınıfa, IntentService ‘dan kalıtım alın. OnHandleIntent () metodunda etkinliklerin listesi elde edilir ve LocalBroadcastManager kullanılarak yayınlanacaktır.
12345678910111213141516171819202122232425262728293031323334353637383940import android.app.IntentService;import android.content.Intent;import android.support.v4.content.LocalBroadcastManager;import android.util.Log;import com.google.android.gms.location.ActivityRecognitionResult;import com.google.android.gms.location.DetectedActivity;import java.util.ArrayList;public class DetectedActivitiesIntentService extends IntentService {protected static final String TAG = DetectedActivitiesIntentService.class.getSimpleName();public DetectedActivitiesIntentService() {super(TAG);}@Overridepublic void onCreate() {super.onCreate();}@SuppressWarnings("unchecked")@Overrideprotected void onHandleIntent(Intent intent) {ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);// Cihazın geçerli durumu ile ilgili olası aktivitelerin listesini alırArrayList detectedActivities = (ArrayList) result.getProbableActivities();//Döngü ile tüm yapılan faaliyetlerin tipini ve faaliyetin doğruluğu hakkında bilgi verir.(Değer 0 ile 100 arasındadır)for (DetectedActivity activity : detectedActivities) {Log.e(TAG, "Algılanan faaliyet: " + activity.getType() + ", " + activity.getConfidence());broadcastActivity(activity);}}private void broadcastActivity(DetectedActivity activity) {Intent intent = new Intent(Constants.BROADCAST_DETECTED_ACTIVITY);intent.putExtra("type", activity.getType());intent.putExtra("confidence", activity.getConfidence());LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}} - Arka planda çalışacak olan ve belirli aralıklıklarla kullanıcının faaliyetleri tespit edecek Android servis sınıfını oluşturmamız gerekir.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.util.Log;import android.widget.Toast;import com.google.android.gms.location.ActivityRecognitionClient;import com.google.android.gms.tasks.OnFailureListener;import com.google.android.gms.tasks.OnSuccessListener;import com.google.android.gms.tasks.Task;public class BackgroundDetectedActivitiesService extends Service {private static final String TAG = BackgroundDetectedActivitiesService.class.getSimpleName();private Intent mIntentService;private PendingIntent mPendingIntent;private ActivityRecognitionClient mActivityRecognitionClient;IBinder mBinder = new BackgroundDetectedActivitiesService.LocalBinder();public class LocalBinder extends Binder {public BackgroundDetectedActivitiesService getServerInstance() {return BackgroundDetectedActivitiesService.this;}}@Overridepublic void onCreate() {super.onCreate();mActivityRecognitionClient = new ActivityRecognitionClient(this);mIntentService = new Intent(this, DetectedActivitiesIntentService.class);mPendingIntent = PendingIntent.getService(this, 1, mIntentService, PendingIntent.FLAG_UPDATE_CURRENT);requestActivityUpdatesButtonHandler();}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {super.onStartCommand(intent, flags, startId);return START_STICKY;}public void requestActivityUpdatesButtonHandler() {Task task = mActivityRecognitionClient.requestActivityUpdates(Constants.DETECTION_INTERVAL_IN_MILLISECONDS,mPendingIntent);task.addOnSuccessListener(new OnSuccessListener() {@Overridepublic void onSuccess(Void result) {Toast.makeText(getApplicationContext(),"Başarıyla talep edilen etkinlik güncellemeleri",Toast.LENGTH_SHORT).show();}});task.addOnFailureListener(new OnFailureListener() {@Overridepublic void onFailure(@NonNull Exception e) {Toast.makeText(getApplicationContext(),"Etkinlik güncelleme talep etme başarısız oldu",Toast.LENGTH_SHORT).show();}});}public void removeActivityUpdatesButtonHandler() {Task task = mActivityRecognitionClient.removeActivityUpdates(mPendingIntent);task.addOnSuccessListener(new OnSuccessListener() {@Overridepublic void onSuccess(Void result) {Toast.makeText(getApplicationContext(),"Etkinlik güncellemeleri başarıyla kaldırdı!",Toast.LENGTH_SHORT).show();}});task.addOnFailureListener(new OnFailureListener() {@Overridepublic void onFailure(@NonNull Exception e) {Toast.makeText(getApplicationContext(), "Etkinlik güncellemeleri kaldırılamadı!",Toast.LENGTH_SHORT).show();}});}@Overridepublic void onDestroy() {super.onDestroy();removeActivityUpdatesButtonHandler();}} - BackgroundDetectedActivitiesService ve DetectedActivitiesIntentService servis sınıflarını AndroidManifest.xml dosyasında tanımlamamız gerekir. Birde AndroidManifest.xml dosyasında ACTIVITY_RECOGNITION iznini vermemiz gerekir.
123456789101112131415161718192021222324252627<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.smality.activityrecognition"><uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><serviceandroid:name=".DetectedActivitiesIntentService" android:exported="false" /><service android:name=".BackgroundDetectedActivitiesService"></service></application></manifest>
3-Activity Recognition
Şimdi herşeye hazırız. Kullanıcının yaptığı güncel aktiviteyi veya herhangi bir başka aktivite yaptığında bunun bilgisini nasıl alacağımızı görelim.
- ImageView (etkinliği temsil eden bir simge görüntülemek için) ve TextView (etkinliği görüntülemek için) ekliyoruz. Ayrıca, etkinlik tanıma hizmetini başlatmak ve başlatmak için iki button ekledim.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="16dp"tools:context="com.smality.activityrecognition.MainActivity"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="vertical"><ImageViewandroid:id="@+id/img_activity"android:layout_width="wrap_content"android:layout_height="200dp"android:tint="#606060" /><TextViewandroid:id="@+id/txt_activity"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:textAllCaps="true"android:textColor="@color/colorPrimary"android:textSize="18dp"android:textStyle="bold" /><TextViewandroid:id="@+id/txt_confidence"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginTop="10dp"android:textAllCaps="true"android:textSize="14dp" /></LinearLayout><Buttonandroid:id="@+id/btn_start_tracking"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:text="Start Tracking" /><Buttonandroid:id="@+id/btn_stop_tracking"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:text="Stop Tracking" /></RelativeLayout> - MainActivity sınıfında kullanılan startTracking() ve stopTracking() metodlar,hizmet durumunu değiştirerek kullanıcı etkinliği güncellemelerini başlatır veya durdurur. BroadcastReceiver sınıfı, IntentService’den etkinlik güncellemelerini almak için kullanılır. handleUserActivity() metodu, kullanıcının yaptığı güncel aktivite tipini,aktivitenin doğruluğu bilgisini kullanarak arayüzde ilgili faaliyetin resmini ve doğruluk bilgisini gösterir.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.support.v4.content.LocalBroadcastManager;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;import com.google.android.gms.location.DetectedActivity;public class MainActivity extends AppCompatActivity {private String TAG = MainActivity.class.getSimpleName();BroadcastReceiver broadcastReceiver;private TextView txtActivity, txtConfidence;private ImageView imgActivity;private Button btnStartTrcking, btnStopTracking;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);txtActivity = findViewById(R.id.txt_activity);txtConfidence = findViewById(R.id.txt_confidence);imgActivity = findViewById(R.id.img_activity);btnStartTrcking = findViewById(R.id.btn_start_tracking);btnStopTracking = findViewById(R.id.btn_stop_tracking);btnStartTrcking.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {startTracking();}});btnStopTracking.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {stopTracking();}});broadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(Constants.BROADCAST_DETECTED_ACTIVITY)) {int type = intent.getIntExtra("type", -1);int confidence = intent.getIntExtra("confidence", 0);handleUserActivity(type, confidence);}}};startTracking();}private void handleUserActivity(int type, int confidence) {String label = getString(R.string.activity_unknown);int icon = R.drawable.ic_still;switch (type) {case DetectedActivity.IN_VEHICLE: {label = getString(R.string.activity_in_vehicle);icon = R.drawable.ic_driving;break;}case DetectedActivity.ON_BICYCLE: {label = getString(R.string.activity_on_bicycle);icon = R.drawable.ic_on_bicycle;break;}case DetectedActivity.ON_FOOT: {label = getString(R.string.activity_on_foot);icon = R.drawable.ic_walking;break;}case DetectedActivity.RUNNING: {label = getString(R.string.activity_running);icon = R.drawable.ic_running;break;}case DetectedActivity.STILL: {label = getString(R.string.activity_still);break;}case DetectedActivity.TILTING: {label = getString(R.string.activity_tilting);icon = R.drawable.ic_tilting;break;}case DetectedActivity.WALKING: {label = getString(R.string.activity_walking);icon = R.drawable.ic_walking;break;}case DetectedActivity.UNKNOWN: {label = getString(R.string.activity_unknown);break;}}Log.e(TAG, "User activity: " + label + ", Confidence: " + confidence);if (confidence > Constants.CONFIDENCE) {txtActivity.setText(label);txtConfidence.setText("Confidence: " + confidence);imgActivity.setImageResource(icon);}}@Overrideprotected void onResume() {super.onResume();LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver,new IntentFilter(Constants.BROADCAST_DETECTED_ACTIVITY));}@Overrideprotected void onPause() {super.onPause();LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);}private void startTracking() {Intent intent1 = new Intent(MainActivity.this, BackgroundDetectedActivitiesService.class);startService(intent1);}private void stopTracking() {Intent intent = new Intent(MainActivity.this, BackgroundDetectedActivitiesService.class);stopService(intent);}}
Dilerseniz aşağıda vermiş olduğum Kod İndir resmine tıklayarak github’a yüklemiş olduğum projeyi indirip, inceleyebilirsiniz.
Kaynaklar
1-https://smality.com/activity-recognition-ile-kullanici-aktivitelerini-tespit-etme/
2- http://www.androhub.com/android-floating-widget-like-facebook-messenger-chat-head/
3- http://www.androidhive.info/2016/11/android-floating-widget-like-facebook-chat-head/