diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..197174c --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index a9f4e52..a2d7c21 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 0d601bb..5925165 100644 --- a/README.md +++ b/README.md @@ -1 +1,16 @@ -# NewBody \ No newline at end of file +# NewBody +Google MLkit를 이용한 자세인식 홈트레이닝 어플(Android) + +# 기술 스택 +image + +# 앱 화면 +- 시작 화면 +![image](https://github.com/ohwoonwan/NewBody/assets/111224337/948b030f-37db-467e-8368-f0f3bc62b0bb) + +- 로그인 & 회원가입 +![image](https://github.com/ohwoonwan/NewBody/assets/111224337/336190b8-aec9-4b8a-b395-f9ea2e54cac7) + +- 메뉴 +![image](https://github.com/ohwoonwan/NewBody/assets/111224337/b9c5060d-dda0-4631-8427-4bed248b1f2e) + diff --git a/app/build.gradle b/app/build.gradle index 1cf2ea5..6d27cfe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.application' + id 'com.google.gms.google-services' } android { @@ -29,11 +30,54 @@ android { } dependencies { - + implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.google.firebase:firebase-auth-ktx:22.1.1' + implementation 'com.google.firebase:firebase-auth:22.1.1' + implementation 'com.google.firebase:firebase-firestore:24.7.1' + implementation 'com.google.android.gms:play-services-auth:20.6.0' + implementation(platform("com.google.firebase:firebase-bom:32.2.2")) + implementation 'com.google.firebase:firebase-analytics' + implementation 'com.google.firebase:firebase-database-ktx:20.2.2' + implementation 'com.google.firebase:firebase-storage-ktx:20.2.1' + implementation 'com.google.firebase:firebase-firestore-ktx:24.7.1' + implementation 'de.hdodenhof:circleimageview:3.1.0' + implementation 'com.github.bumptech.glide:glide:4.12.0' + implementation 'com.google.firebase:firebase-messaging:23.0.3' + implementation 'com.google.firebase:firebase-dynamic-links' + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' + implementation 'jp.wasabeef:glide-transformations:4.3.0' + implementation 'com.google.firebase:firebase-storage:20.2.1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' -} \ No newline at end of file + implementation 'com.google.mlkit:pose-detection-accurate:17.0.1-beta2' + implementation 'com.squareup.picasso:picasso:2.71828' + implementation 'com.google.code.gson:gson:2.10.1' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' + implementation 'com.jakewharton:butterknife:10.2.3' + implementation 'com.google.guava:guava:27.0.1-android' + + implementation 'com.github.bumptech.glide:glide:4.11.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' + implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' + + implementation 'com.android.volley:volley:1.2.1' + implementation 'com.google.code.gson:gson:2.10.1' + + implementation 'io.github.bootpay:android:+' + implementation 'com.google.android.gms:play-services-ads:22.3.0' + + def camerax_version = "1.0.0-beta07" + // CameraX core library using camera2 implementation + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle Library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:1.0.0-alpha14" +} + + +apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..86037a2 --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,40 @@ +{ + "project_info": { + "project_number": "1055116036920", + "firebase_url": "https://newbody-68ce0-default-rtdb.firebaseio.com", + "project_id": "newbody-68ce0", + "storage_bucket": "newbody-68ce0.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1055116036920:android:1b4466be83eff432a10fcd", + "android_client_info": { + "package_name": "com.example.newbody" + } + }, + "oauth_client": [ + { + "client_id": "1055116036920-5s68ogbrje2iruknd5bodeifobimfek2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDCc8RJ5hJ1Xj_xXbYeEYeD_CzKTJmQ8-U" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1055116036920-5s68ogbrje2iruknd5bodeifobimfek2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2e684a3..fd2b9b9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,15 +2,35 @@ + + + + + + + + + + + + + + + @@ -20,6 +40,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Calendar.java b/app/src/main/java/com/example/newbody/Calendar.java new file mode 100644 index 0000000..f4a3be1 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Calendar.java @@ -0,0 +1,240 @@ +package com.example.newbody; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CalendarView; +import android.widget.EditText; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; + +import java.util.ArrayList; + + +public class Calendar extends Fragment { + private View view, mic_button; + private String readDay = null; + private String str = null; + private CalendarView calendarView; + private Button cha_Btn, del_Btn, save_Btn; + private TextView diaryTextView, textView2, textView3; + private EditText contextEditText; + + private FirebaseAuth auth; + + private FirebaseUser user; + private DatabaseReference databaseReference; + + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + view = inflater.inflate(R.layout.activity_calendar, container, false); + + calendarView = view.findViewById(R.id.calendarView); + diaryTextView = view.findViewById(R.id.diaryTextView); + save_Btn = view.findViewById(R.id.save_Btn); + del_Btn = view.findViewById(R.id.del_Btn); + cha_Btn = view.findViewById(R.id.cha_Btn); + textView2 = view.findViewById(R.id.textView2); + contextEditText = view.findViewById(R.id.contextEditText); + mic_button = view.findViewById(R.id.mic_button); + auth = FirebaseAuth.getInstance(); + user = auth.getCurrentUser(); + // Firebase 데이터베이스 참조를 초기화합니다. + databaseReference = FirebaseDatabase.getInstance().getReference("Calender").child(user.getUid()); + + // Firebase에 접근하기위한 객체 초기화 + calendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() { + @Override + public void onSelectedDayChange(@NonNull CalendarView view, int year, int month, int dayOfMonth) { + diaryTextView.setVisibility(View.VISIBLE); + save_Btn.setVisibility(View.VISIBLE); + contextEditText.setVisibility(View.VISIBLE); + textView2.setVisibility(View.INVISIBLE); + cha_Btn.setVisibility(View.INVISIBLE); + del_Btn.setVisibility(View.INVISIBLE); + mic_button.setVisibility(View.VISIBLE); + diaryTextView.setText(String.format("%d / %d / %d", year, month + 1, dayOfMonth)); + contextEditText.setText(""); + checkDay(year, month, dayOfMonth); + } + }); + + mic_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + }); + + save_Btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + saveDiary(readDay); + str = contextEditText.getText().toString(); + textView2.setText(str); + save_Btn.setVisibility(View.INVISIBLE); + cha_Btn.setVisibility(View.VISIBLE); + del_Btn.setVisibility(View.VISIBLE); + mic_button.setVisibility(View.INVISIBLE); + contextEditText.setVisibility(View.INVISIBLE); + textView2.setVisibility(View.VISIBLE); + } + }); + return view; + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); // 10초 + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 5000); // 5초 + startActivityForResult(intent, 2); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + contextEditText.setText(str); + } + } + public void checkDay(int cYear, int cMonth, int cDay) { + readDay = "" + cYear + "-" + (cMonth + 1) + "" + "-" + cDay; + DatabaseReference dateRef = databaseReference.child(readDay); + + dateRef.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + if (snapshot.exists()) { + // Diary entry exists for the selected date + String content = snapshot.getValue(String.class); + textView2.setText(content); + + // 데이터가 있으므로 textView2를 보여주고 contextEditText를 숨깁니다. + textView2.setVisibility(View.VISIBLE); + contextEditText.setVisibility(View.INVISIBLE); + mic_button.setVisibility(View.INVISIBLE); + + // 저장 버튼을 보여주고 수정, 삭제 버튼을 숨깁니다. + save_Btn.setVisibility(View.INVISIBLE); + cha_Btn.setVisibility(View.VISIBLE); + del_Btn.setVisibility(View.VISIBLE); + } else { + // Diary entry does not exist for the selected date + textView2.setVisibility(View.INVISIBLE); + + diaryTextView.setVisibility(View.VISIBLE); + mic_button.setVisibility(View.VISIBLE); + save_Btn.setVisibility(View.VISIBLE); + cha_Btn.setVisibility(View.INVISIBLE); + del_Btn.setVisibility(View.INVISIBLE); + contextEditText.setVisibility(View.VISIBLE); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + // Error occurred while fetching diary entry + error.toException().printStackTrace(); + } + }); + + + + cha_Btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + contextEditText.setVisibility(View.VISIBLE); + textView2.setVisibility(View.INVISIBLE); + contextEditText.setText(str); + + save_Btn.setVisibility(View.VISIBLE); + cha_Btn.setVisibility(View.INVISIBLE); + del_Btn.setVisibility(View.INVISIBLE); + textView2.setText(contextEditText.getText()); + } + }); + + del_Btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + textView2.setVisibility(View.INVISIBLE); + contextEditText.setText(""); + contextEditText.setVisibility(View.VISIBLE); + save_Btn.setVisibility(View.VISIBLE); + cha_Btn.setVisibility(View.INVISIBLE); + del_Btn.setVisibility(View.INVISIBLE); + + // Remove the diary entry from Firebase Realtime Database + dateRef.removeValue() + .addOnSuccessListener(aVoid -> { + // Diary entry removed successfully + }) + .addOnFailureListener(e -> { + // Error occurred while removing diary entry + e.printStackTrace(); + }); + } + }); + } + + @SuppressLint("WrongConstant") + public void saveDiary(String readDay) { + // Get the content from the EditText + String content = contextEditText.getText().toString(); + + DatabaseReference dateRef = databaseReference.child(readDay); + + // Save the diary entry to Firebase Realtime Database + dateRef.setValue(content) + .addOnSuccessListener(aVoid -> { + // Diary entry saved successfully + }) + .addOnFailureListener(e -> { + // Error occurred while saving diary entry + e.printStackTrace(); + }); + } + +} + diff --git a/app/src/main/java/com/example/newbody/CustomDialog.java b/app/src/main/java/com/example/newbody/CustomDialog.java new file mode 100644 index 0000000..d06b224 --- /dev/null +++ b/app/src/main/java/com/example/newbody/CustomDialog.java @@ -0,0 +1,44 @@ +package com.example.newbody; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.example.newbody.mainInfo.MainActivityA; + +import org.checkerframework.checker.nullness.qual.NonNull; + +public class CustomDialog extends Dialog { + private TextView txt_contents; + private Button shutdownClick; + private Context mContext; + + public CustomDialog(@NonNull Context context, String contents) { + super(context); + mContext = context; + setContentView(R.layout.activity_custom_dialog); + + txt_contents = findViewById(R.id.txt_contents); + txt_contents.setText(contents); + shutdownClick = findViewById(R.id.btn_shutdown); + shutdownClick.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(mContext, Record.class); + mContext.startActivity(intent); + dismiss(); // Dialog를 닫습니다. + + // 해당 Dialog를 호출한 Activity를 종료합니다. + if (mContext instanceof Activity) { + ((Activity) mContext).finish(); + } + } + }); + + } +} diff --git a/app/src/main/java/com/example/newbody/CustomDialogNotice.java b/app/src/main/java/com/example/newbody/CustomDialogNotice.java new file mode 100644 index 0000000..1758691 --- /dev/null +++ b/app/src/main/java/com/example/newbody/CustomDialogNotice.java @@ -0,0 +1,37 @@ +package com.example.newbody; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import org.checkerframework.checker.nullness.qual.NonNull; + +public class CustomDialogNotice extends Dialog { + private TextView txt_contents; + private Button shutdownClick; + private Context mContext; + + public CustomDialogNotice(@NonNull Context context, String contents) { + super(context); + mContext = context; + setContentView(R.layout.activity_custom_dialog_notice); + + txt_contents = findViewById(R.id.txt_contents); + txt_contents.setText(contents); + shutdownClick = findViewById(R.id.btn_shutdown); + shutdownClick.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { +// Intent intent = new Intent(mContext, Home.class); +// mContext.startActivity(intent); + dismiss(); // Dialog를 닫습니다. + } + }); + + } +} diff --git a/app/src/main/java/com/example/newbody/FirebaseMessagingService.java b/app/src/main/java/com/example/newbody/FirebaseMessagingService.java new file mode 100644 index 0000000..384c28e --- /dev/null +++ b/app/src/main/java/com/example/newbody/FirebaseMessagingService.java @@ -0,0 +1,46 @@ +package com.example.newbody; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; + +import androidx.core.app.NotificationCompat; + +import com.google.firebase.messaging.RemoteMessage; + +public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService { + + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + super.onMessageReceived(remoteMessage); + + // 알림의 제목 및 본문을 가져옵니다. + String title = remoteMessage.getData().get("title_key"); + String body = remoteMessage.getData().get("body_key"); + + // 가져온 제목 및 본문으로 알림을 전송합니다. + sendNotification(title, body); + } + + + private void sendNotification(String title, String body) { + Intent intent = new Intent(this, Notice.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra("title", title); + intent.putExtra("body", body); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT); + + NotificationCompat.Builder notificationBuilder = + new NotificationCompat.Builder(this, "channel_id") + .setSmallIcon(R.mipmap.newbody_logo) // 앱 아이콘 + .setContentTitle(title) + .setContentText(body) + .setAutoCancel(true) + .setContentIntent(pendingIntent); + + NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + notificationManager.notify(0, notificationBuilder.build()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/FriendData.java b/app/src/main/java/com/example/newbody/FriendData.java new file mode 100644 index 0000000..2d5b085 --- /dev/null +++ b/app/src/main/java/com/example/newbody/FriendData.java @@ -0,0 +1,101 @@ +package com.example.newbody; + +public class FriendData { + private String name; + private String birth; + private String gender; + private String weight; + + private String height; + private String fcmToken; + + public String getFcmToken() { + return fcmToken; + } + + public void setFcmToken(String fcmToken) { + this.fcmToken = fcmToken; + } + + private String imageUrl; + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + private String uid; + + public String getStatus() { + return status; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public void setStatus(String status) { + this.status = status; + } + + private String status; + + public FriendData() { + + } + + public FriendData(String name, String birth, String uid) { + this.name = name; + this.birth = birth; + this.uid = uid; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getWeight() { + return weight; + } + + public void setWeight(String weight) { + this.weight = weight; + } + + public String getHeight() { + return height; + } + + public void setHeight(String height) { + this.height = height; + } + + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getBirth() { + return birth; + } + + public void setBirth(String birth) { + this.birth = birth; + } + +} diff --git a/app/src/main/java/com/example/newbody/FriendInvite.java b/app/src/main/java/com/example/newbody/FriendInvite.java new file mode 100644 index 0000000..52e7852 --- /dev/null +++ b/app/src/main/java/com/example/newbody/FriendInvite.java @@ -0,0 +1,115 @@ +package com.example.newbody; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import android.Manifest; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.newbody.FriendInviteContact; +import com.example.newbody.R; +import com.example.newbody.RecyclerViewAdapterInvite; + +import java.util.ArrayList; +import java.util.List; + +public class FriendInvite extends AppCompatActivity { + private Button prev; + private Button searchBtn; + + String searchOption = "name"; + private RecyclerView recyclerView; + TextView textView; + private EditText searchEditText; + private RecyclerViewAdapter recyclerViewAdapter; + private RecyclerViewAdapterInvite adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_friend_invite); + + prev = findViewById(R.id.prevButtonFriendInvite2); + recyclerView = findViewById(R.id.recyclerView2); + searchBtn = findViewById(R.id.searchBtn2); + textView = findViewById(R.id.textView2); + searchEditText = findViewById(R.id.searchWord2); + recyclerViewAdapter = new RecyclerViewAdapter(); + // 연락처 데이터를 읽어와서 contactList에 저장 + List contactList = getContactList(); + + // RecyclerViewAdapterInvite 어댑터를 초기화하고 리사이클러뷰에 설정 + adapter = new RecyclerViewAdapterInvite(this, contactList); + recyclerView.setAdapter(adapter); + + // 리사이클러뷰에 LinearLayoutManager 설정 (세로 방향) + LinearLayoutManager layoutManager = new LinearLayoutManager(this); + recyclerView.setLayoutManager(layoutManager); + + // (옵션) 리사이클러뷰에 구분선 추가 + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), + layoutManager.getOrientation()); + recyclerView.addItemDecoration(dividerItemDecoration); + + textView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + searchOption = "name"; + } + }); + searchBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String searchWord = searchEditText.getText().toString(); + String searchOption = "name"; + adapter.performSearch(searchWord, searchOption); // 수정된 부분 + if (adapter.getItemCount() == 0) { + Toast.makeText(FriendInvite.this, "존재하지 않는 이름입니다.", Toast.LENGTH_SHORT).show(); + } + } + }); + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + } + + private List getContactList() { + List contactList = new ArrayList<>(); + + // 연락처 데이터를 읽어오는 코드 + Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, + null, null, null, null); + + if (cursor != null) { + while (cursor.moveToNext()) { + String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); + String phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); + FriendInviteContact contact = new FriendInviteContact(name, phoneNumber); + contactList.add(contact); + } + cursor.close(); + } + + return contactList; + } +} diff --git a/app/src/main/java/com/example/newbody/FriendInviteContact.java b/app/src/main/java/com/example/newbody/FriendInviteContact.java new file mode 100644 index 0000000..9a202fe --- /dev/null +++ b/app/src/main/java/com/example/newbody/FriendInviteContact.java @@ -0,0 +1,20 @@ +package com.example.newbody; + +//연락처 가져오기 +public class FriendInviteContact { + private String name; + private String phoneNumber; + + public FriendInviteContact(String name, String phoneNumber) { + this.name = name; + this.phoneNumber = phoneNumber; + } + + public String getName() { + return name; + } + + public String getPhoneNumber() { + return phoneNumber; + } +} diff --git a/app/src/main/java/com/example/newbody/FriendList.java b/app/src/main/java/com/example/newbody/FriendList.java new file mode 100644 index 0000000..d2ead5a --- /dev/null +++ b/app/src/main/java/com/example/newbody/FriendList.java @@ -0,0 +1,164 @@ +package com.example.newbody; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.util.Base64; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.newbody.FriendData; +import com.google.firebase.firestore.FirebaseFirestore; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; + +public class FriendList extends AppCompatActivity { + + TextView textView; + private FirebaseFirestore firestore; + String searchOption = "name"; + + private Button searchBtn; + private EditText searchEditText; + + private RecyclerViewAdapter recyclerViewAdapter; + private Button prev; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_friend_list); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + searchBtn = findViewById(R.id.searchBtn); + searchEditText = findViewById(R.id.searchWord); + textView = findViewById(R.id.textView); + prev = findViewById(R.id.prevButtonFriendAdd); + + // 파이어스토어 인스턴스 초기화 + firestore = FirebaseFirestore.getInstance(); + + recyclerViewAdapter = new RecyclerViewAdapter(); + RecyclerView recyclerView = findViewById(R.id.recyclerview); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(recyclerViewAdapter); + + textView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + searchOption = "name"; + } + }); + + searchBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String searchWord = searchEditText.getText().toString(); + String searchOption = "name"; + recyclerViewAdapter.performSearch(searchWord, searchOption); + if (recyclerViewAdapter.getItemCount() == 0) { + Toast.makeText(FriendList.this, "존재하지 않는 이름입니다.", Toast.LENGTH_SHORT).show(); + } + } + }); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/FriendListPlus.java b/app/src/main/java/com/example/newbody/FriendListPlus.java new file mode 100644 index 0000000..370f550 --- /dev/null +++ b/app/src/main/java/com/example/newbody/FriendListPlus.java @@ -0,0 +1,163 @@ +package com.example.newbody; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; + +import com.example.newbody.FriendData; +import com.example.newbody.R; +import com.example.newbody.RecyclerViewAdapterPlus; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.QueryDocumentSnapshot; + +import java.util.ArrayList; + +public class FriendListPlus extends AppCompatActivity { + + private RecyclerView mRecyclerView; + private RecyclerViewAdapterPlus mRecyclerAdapter; + private FirebaseFirestore db; + + private Button FriendRequestBt; + private Button prev; + + private Button DeleteBtn; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_friend_list11); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); + + mRecyclerAdapter = new RecyclerViewAdapterPlus(); + + prev = findViewById(R.id.prevButtonFriendList); + DeleteBtn = findViewById(R.id.deleteBtn); + mRecyclerView.setAdapter(mRecyclerAdapter); + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + + db = FirebaseFirestore.getInstance(); + String currentUid = FirebaseAuth.getInstance().getCurrentUser().getUid(); + db.collection("users").document(currentUid) + .collection("friends") + .get() + .addOnSuccessListener(queryDocumentSnapshots -> { + ArrayList friendList = new ArrayList<>(); + for (QueryDocumentSnapshot document : queryDocumentSnapshots) { + FriendData friend = document.toObject(FriendData.class); + friendList.add(friend); + } + mRecyclerAdapter.setFriendList(friendList); + }) + .addOnFailureListener(e -> { + // 실패 처리 + }); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + DeleteBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + // 삭제 버튼이 눌렸을 때의 동작 + String currentUserUid = FirebaseAuth.getInstance().getCurrentUser().getUid(); + mRecyclerAdapter.deleteSelectedItems(currentUserUid); + } + }); + + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Graph.java b/app/src/main/java/com/example/newbody/Graph.java new file mode 100644 index 0000000..277e954 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Graph.java @@ -0,0 +1,537 @@ +package com.example.newbody; + +import android.app.Activity; +import android.app.DatePickerDialog; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Color; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.NumberPicker; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.DialogFragment; + +import com.github.mikephil.charting.charts.Chart; +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.data.LineDataSet; +import com.github.mikephil.charting.formatter.ValueFormatter; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +public class Graph extends AppCompatActivity implements OnDateSetListener { + + private Button exerciseGraph, exerciseRange, graphView, prev, selectCalendar; + private Chart chartView, chartView2; + private String select_ex, select_range; + private FirebaseFirestore db; + private FirebaseUser user; + private LineChart chart, chart2; + private TextView dateSelect; + private View dateView; + SimpleDateFormat yy, mm; + Date date; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_graph); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + chart = findViewById(R.id.chart); + chart2 = findViewById(R.id.chart2); + exerciseGraph = findViewById(R.id.exerciseGraph); + exerciseRange = findViewById(R.id.graphRange); + selectCalendar = findViewById(R.id.selectDate); + dateSelect = findViewById(R.id.calendarText); + dateView = findViewById(R.id.calendarSelect); + graphView = findViewById(R.id.graph_info_button); + chartView = findViewById(R.id.chart); + prev = findViewById(R.id.prevButtonGraph); + db = FirebaseFirestore.getInstance(); + user = FirebaseAuth.getInstance().getCurrentUser(); + + date = new Date(); + yy = new SimpleDateFormat("yyyy"); + mm = new SimpleDateFormat("MM"); + + exerciseRange.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showRangeDialog(); + } + }); + + exerciseGraph.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) {showExerciseDialog();} + }); + + graphView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(exerciseRange.getText().equals("범위")){ + Toast.makeText(Graph.this, "범위를 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(exerciseGraph.getText().equals("운동")){ + Toast.makeText(Graph.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(exerciseRange.getText().equals("월별 통계")){ + int yearNum = Integer.parseInt(yy.format(date)); + int mmNum = Integer.parseInt(mm.format(date)); + dateView.setVisibility(View.VISIBLE); + chart.setVisibility(View.GONE); + chart2.setVisibility(View.VISIBLE); + dateSelect.setText(yearNum + "년 " + mmNum + "월 "); + loadMonthlyData(yearNum, mmNum); + }else if(exerciseRange.getText().equals("최근 7일")){ + chart.setVisibility(View.VISIBLE); + chart2.setVisibility(View.GONE); + dateView.setVisibility(View.INVISIBLE); + loadLast7DaysSquatData(); + } + } + }); + + selectCalendar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showDatePickerDialog(view); + } + }); + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + } + + @Override + public void onDateSet(int year, int month) { + dateSelect.setText(year + "년 " + (month + 1) + "월"); + } + + private void showRangeDialog() { + final String[] exOptions = {"월별 통계", "최근 7일"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("범위 선택"); + builder.setItems(exOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_range = exOptions[which]; + exerciseRange.setText(select_range); + } + }); + builder.show(); + } + + private void showExerciseDialog() { + final String[] exOptions = {"스쿼트", "푸쉬업", "덤벨 숄더 프레스", "사이드 레터럴 레이즈", "레그 레이즈", "덤벨 컬", "덤벨 플라이", "덤벨 트라이셉스 익스텐션"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("운동 선택"); + builder.setItems(exOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_ex = exOptions[which]; + exerciseGraph.setText(select_ex); + } + }); + builder.show(); + } + + private void loadLast7DaysSquatData() { + final List last7Days = new ArrayList<>(); + DateFormat dateFormat = new SimpleDateFormat("MMdd"); + Calendar cal = Calendar.getInstance(); + for (int i = 0; i < 7; i++) { + last7Days.add(dateFormat.format(cal.getTime())); + cal.add(Calendar.DAY_OF_MONTH, -1); + } + + Collections.reverse(last7Days); + + String collectionName = null; + String exercise = null; + + if (exerciseGraph.getText().equals("스쿼트")) { + collectionName = "dailySquatRecords"; + exercise = "squatCount"; + } else if (exerciseGraph.getText().equals("푸쉬업")) { + collectionName = "dailyPushupRecords"; + exercise = "pushupCount"; + } else if (exerciseGraph.getText().equals("덤벨 숄더 프레스")) { + collectionName = "dailyDumbbellRecords"; + exercise = "dumbbellCount"; + } else if (exerciseGraph.getText().equals("사이드 레터럴 레이즈")) { + collectionName = "dailySideRecords"; + exercise = "sideCount"; + } else if (exerciseGraph.getText().equals("레그 레이즈")) { + collectionName = "dailyLegRecords"; + exercise = "legCount"; + }else if(exerciseGraph.getText().equals("덤벨 컬")){ + collectionName = "dailyCurlRecords"; + exercise = "CurlCount"; + }else if(exerciseGraph.getText().equals("덤벨 플라이")){ + collectionName = "dailyFlyRecords"; + exercise = "flyCount"; + }else if(exerciseGraph.getText().equals("덤벨 트라이셉스 익스텐션")){ + collectionName = "dailyTricepsRecords"; + exercise = "tricepsCount"; + } + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + + List entries = new ArrayList<>(); + for (int i = 0; i < last7Days.size(); i++) { + final int index = i; + final String date = last7Days.get(i); + + String finalExercise = exercise; + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + Long exerciseCount = document.getLong("2023"+date + finalExercise); + if (exerciseCount == null) { + exerciseCount = 0L; + } + entries.add(new Entry(index, exerciseCount)); + if (index == last7Days.size() - 1) { + drawGraph(entries, last7Days); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + } + + private void loadMonthlyData(int year, int month) { + String collectionName = null; + String exercise = null; + + if (exerciseGraph.getText().equals("스쿼트")) { + collectionName = "dailySquatRecords"; + exercise = "squatCount"; + } else if (exerciseGraph.getText().equals("푸쉬업")) { + collectionName = "dailyPushupRecords"; + exercise = "pushupCount"; + } else if (exerciseGraph.getText().equals("덤벨 숄더 프레스")) { + collectionName = "dailyDumbbellRecords"; + exercise = "dumbbellCount"; + } else if (exerciseGraph.getText().equals("사이드 레터럴 레이즈")) { + collectionName = "dailySideRecords"; + exercise = "sideCount"; + } else if (exerciseGraph.getText().equals("레그 레이즈")) { + collectionName = "dailyLegRecords"; + exercise = "legCount"; + } else if(exerciseGraph.getText().equals("덤벨 컬")){ + collectionName = "dailyCurlRecords"; + exercise = "CurlCount"; + } else if(exerciseGraph.getText().equals("덤벨 플라이")){ + collectionName = "dailyFlyRecords"; + exercise = "flyCount"; + } else if(exerciseGraph.getText().equals("덤벨 트라이셉스 익스텐션")){ + collectionName = "dailyTricepsRecords"; + exercise = "tricepsCount"; + } + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + + // 해당 연도와 달에 해당하는 날짜 범위를 설정합니다. + int lastDay = Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH); + List entries = new ArrayList<>(); + for (int day = 1; day <= lastDay; day++) { + final int index = day - 1; + final String date = String.format("%04d%02d%02d", year, month, day); + + String finalExercise = exercise; + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + Long exerciseCount = document.getLong(date + finalExercise); + if (exerciseCount == null) { + exerciseCount = 0L; + } + entries.add(new Entry(index, exerciseCount)); + if (index == lastDay - 1) { + drawMonthGraph(entries, year, month, lastDay); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + } + + private void drawGraph(List entries, final List last7Days) { + LineDataSet dataSet = new LineDataSet(entries, exerciseGraph.getText() + " 그래프"); + + dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); + dataSet.setLineWidth(2f); + dataSet.setColor(Color.parseColor("#9DCEFF")); + dataSet.setCircleColor(Color.parseColor("#9DCEFF")); + + LineData lineData = new LineData(dataSet); + + chart.getXAxis().setValueFormatter(new ValueFormatter() { + @Override + public String getFormattedValue(float value) { + if (value >= 0 && value < last7Days.size()) { + return last7Days.get((int) value); + } + return ""; + } + }); + + chart.getAxisRight().setEnabled(false); + + chart.setData(lineData); + chart.invalidate(); + } + + private void drawMonthGraph(List entries, int year, int month, int lastDay) { + LineDataSet dataSet = new LineDataSet(entries, exerciseGraph.getText() + " 그래프"); + + dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); + dataSet.setLineWidth(2f); + dataSet.setColor(Color.parseColor("#9DCEFF")); + dataSet.setCircleColor(Color.parseColor("#9DCEFF")); + + LineData lineData = new LineData(dataSet); + + chart2.getXAxis().setValueFormatter(new ValueFormatter() { + @Override + public String getFormattedValue(float value) { + if (value >= 0 && value < lastDay) { + return String.format("%02d", (int)value + 1); + } + return ""; + } + }); + + chart2.getAxisRight().setEnabled(false); + + chart2.setData(lineData); + chart2.invalidate(); + + // 한 화면에 7개의 데이터 포인트만 보이도록 설정 + chart2.setVisibleXRangeMaximum(7); + // 최초로 마지막 7개의 데이터 포인트를 보여줌 + chart2.moveViewToX(0); + } + + + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("스쿼트") || str.equals("푸쉬업") || str.equals("푸시업") || str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스") || + str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈") || str.equals("레그 레이즈") || str.equals("레그레이즈") || + str.equals("덤벨컬") || str.equals("덤벨 컬") || str.equals("덤벨 플라이") || str.equals("덤벨플라이") || str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + if(str.equals("스쿼트")){ + select_ex = "스쿼트"; + exerciseGraph.setText(select_ex); + }else if(str.equals("푸쉬업") || str.equals("푸시업")){ + select_ex = "푸쉬업"; + exerciseGraph.setText(select_ex); + }else if(str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스")){ + select_ex = "덤벨 숄더 프레스"; + exerciseGraph.setText(select_ex); + }else if(str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈")){ + select_ex = "사이드 레터럴 레이즈"; + exerciseGraph.setText(select_ex); + }else if(str.equals("레그 레이즈") || str.equals("레그레이즈")){ + select_ex = "레그 레이즈"; + exerciseGraph.setText(select_ex); + }else if(str.equals("덤벨컬") || str.equals("덤벨 컬")){ + select_ex = "덤벨 컬"; + exerciseGraph.setText(select_ex); + }else if(str.equals("덤벨 플라이") || str.equals("덤벨플라이")){ + select_ex = "덤벨 플라이"; + exerciseGraph.setText(select_ex); + }else if(str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + select_ex = "덤벨 트라이셉스 익스텐션"; + exerciseGraph.setText(select_ex); + } + } else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } else if(str.equals("조회") || str.equals("그래프 조회") || str.equals("그래프")){ + if(exerciseGraph.getText().equals("운동")){ + Toast.makeText(Graph.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + chart.setVisibility(View.VISIBLE); + loadLast7DaysSquatData(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + public void showDatePickerDialog(View v) { + YearMonthPickerDialog dialog = new YearMonthPickerDialog(); + dialog.setListener(new OnDateSetListener() { + @Override + public void onDateSet(int year, int month) { + // 여기에 로직 추가 + dateSelect.setText(year + "년 " + month + "월"); + loadMonthlyData(year, month); + } + }); + dialog.show(getSupportFragmentManager(), "YearMonthPickerDialog"); + + } + + + public static class YearMonthPickerDialog extends DialogFragment { + private static final int MAX_YEAR = 2099; + private static final int MIN_YEAR = 2000; + + private OnDateSetListener listener; + + public void setListener(OnDateSetListener listener) { + this.listener = listener; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + + View dialog = inflater.inflate(R.layout.year_month_picker, null); + final NumberPicker monthPicker = dialog.findViewById(R.id.monthPicker); + final NumberPicker yearPicker = dialog.findViewById(R.id.yearPicker); + + monthPicker.setMinValue(1); + monthPicker.setMaxValue(12); + monthPicker.setValue(1); + + int year = Calendar.getInstance().get(Calendar.YEAR); + yearPicker.setMinValue(MIN_YEAR); + yearPicker.setMaxValue(MAX_YEAR); + yearPicker.setValue(year); + + builder.setView(dialog) + .setPositiveButton("확인", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + if (listener != null) { + listener.onDateSet(yearPicker.getValue(), monthPicker.getValue()); + } + } + }) + .setNegativeButton("취소", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + YearMonthPickerDialog.this.getDialog().cancel(); + } + }); + return builder.create(); + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Home.java b/app/src/main/java/com/example/newbody/Home.java new file mode 100644 index 0000000..5886728 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Home.java @@ -0,0 +1,228 @@ +package com.example.newbody; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.example.newbody.record.RecordSquatMain; +import com.github.mikephil.charting.charts.PieChart; +import com.github.mikephil.charting.data.PieData; +import com.github.mikephil.charting.data.PieDataSet; +import com.github.mikephil.charting.data.PieEntry; +import com.github.mikephil.charting.formatter.PercentFormatter; +import com.google.android.gms.ads.AdRequest; +import com.google.android.gms.ads.AdView; +import com.google.android.gms.ads.MobileAds; +import com.google.android.gms.ads.initialization.InitializationStatus; +import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; + +import java.util.ArrayList; +import java.util.List; + +public class Home extends Fragment { + private View view, yoga, yoga_lock; + private View posture_button, video_button, record_button, ranking_button, yoga_button, yoga_lock_button; + private PieChart pieChart; + private Button notice; + private CustomDialogNotice customDialog; + private ImageView premium; + private AdView mAdView; + + FirebaseAuth auth; + FirebaseUser user; + FirebaseFirestore db; + TextView name, bmiResult; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + view = inflater.inflate(R.layout.activity_home, container, false); + + yoga = view.findViewById(R.id.yoga_layout); + yoga_lock = view.findViewById(R.id.yoga_lock_layout); + + db = FirebaseFirestore.getInstance(); + auth = FirebaseAuth.getInstance(); + user = auth.getCurrentUser(); + posture_button = view.findViewById(R.id.posture_button); + video_button = view.findViewById(R.id.video_button); + record_button = view.findViewById(R.id.record_button); + ranking_button = view.findViewById(R.id.ranking_button); + yoga_button = view.findViewById(R.id.yoga_button); + yoga_lock_button = view.findViewById(R.id.yoga_lock_button); + pieChart = view.findViewById(R.id.pieChart); + notice = view.findViewById(R.id.noticeDialog); + premium = view.findViewById(R.id.premium_badge); + + name = view.findViewById(R.id.name_info); + bmiResult = view.findViewById(R.id.bmi_result); + mAdView = view.findViewById(R.id.adView); + + AdRequest adRequest = new AdRequest.Builder().build(); + mAdView.loadAd(adRequest); + + premiumCheck(); + + if(user == null){ + Intent intent = new Intent(getActivity(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + int weight = Integer.parseInt(document.getString("weight")); + int height = Integer.parseInt(document.getString("height")); + + double bmiNum = (double)weight/(((double)height/100)*((double)height/100)); + if(bmiNum < 18.5){ + bmiResult.setText("당신의 BMI수치는 저체중에 해당합니다. "); + }else if(bmiNum >= 18.5 && bmiNum < 25){ + bmiResult.setText("당신의 BMI수치는 정상입니다. "); + }else if(bmiNum >= 25 && bmiNum < 30){ + bmiResult.setText("당신의 BMI수치는 과체중에 해당합니다. "); + }else if(bmiNum >= 30){ + bmiResult.setText("당신의 BMI수치는 비만에 해당합니다. "); + } + name.setText(document.getString("name")); + + String bmi = String.valueOf(bmiNum); + + List entries = new ArrayList<>(); + entries.add(new PieEntry((float) bmiNum, "")); + entries.add(new PieEntry(100-(float)bmiNum, "")); + +// Log.d("BmiChart", "BMI: " + bmi); + + PieDataSet dataSet = new PieDataSet(entries, ""); + dataSet.setColors(Color.parseColor("#C58BF2"), Color.WHITE); +// dataSet.setDrawValues(false); + dataSet.setValueTextColor(Color.WHITE); + dataSet.setValueTextSize(14f); + + PieData pieData = new PieData(dataSet); + pieData.setValueFormatter(new PercentFormatter(pieChart)); + pieChart.setData(pieData); + pieChart.getDescription().setEnabled(false); + pieChart.setDrawHoleEnabled(false); + pieChart.getLegend().setEnabled(false); + pieChart.invalidate(); + pieChart.highlightValue(0, 0); + } else { + } + } else { + // handle the failure case + } + } + }); + } + + notice.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + customDialog = new CustomDialogNotice(getContext(), + "본 앱은 음성 인식을 지원합니다. \n\n앱 내에서 '바디'를 불러보세요 ! \n\n'바디야' 또는 '뉴바디'라고 말하면 \n\n바디가 대답해주고 \n\n" + + "명령을 실행해줍니다. " + "\n\n\n" + "예시) 자세 교정, 기록 측정 등"); + customDialog.show(); + } + }); + + posture_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), Posture.class); + startActivity(intent); + } + }); + video_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), Video.class); + startActivity(intent); + } + }); + record_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), Record.class); + startActivity(intent); + } + }); + ranking_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), Ranking.class); + startActivity(intent); + } + }); + + yoga_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), YogaPosture.class); + startActivity(intent); + } + }); + + yoga_lock_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(getActivity(), "프리미엄 회원 전용 메뉴입니다", Toast.LENGTH_SHORT).show(); + } + }); + + return view; + } + + public void premiumCheck(){ + if(user == null){ + Intent intent = new Intent(getActivity(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String grade = document.getString("grade"); + if (grade == null) grade = "일반"; + + if(grade.equals("프리미엄")){ + premium.setVisibility(View.VISIBLE); + yoga.setVisibility(View.VISIBLE); + yoga_lock.setVisibility(View.GONE); + } + } + } else { + } + } + }); + } + } + +} diff --git a/app/src/main/java/com/example/newbody/ImageAdapterGridView.java b/app/src/main/java/com/example/newbody/ImageAdapterGridView.java new file mode 100644 index 0000000..3de6111 --- /dev/null +++ b/app/src/main/java/com/example/newbody/ImageAdapterGridView.java @@ -0,0 +1,85 @@ +package com.example.newbody; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.GridView; +import android.widget.ImageView; + +import java.util.ArrayList; + +public class ImageAdapterGridView extends BaseAdapter { + private Context mContext; + ArrayList itemList = new ArrayList(); + + public ImageAdapterGridView(Context c, ArrayList itemList) { + mContext = c; + this.itemList = itemList; + } + + @Override + public int getCount() { + return itemList.size(); + } + + @Override + public Object getItem(int position) { + return itemList.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ImageView imageView; + if (convertView == null) { // if it's not recycled, initialize some attributes + imageView = new ImageView(mContext); + imageView.setLayoutParams(new GridView.LayoutParams(85, 85)); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setPadding(8, 8, 8, 8); + } else { + imageView = (ImageView) convertView; + } + + Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220, 220); + + imageView.setImageBitmap(bm); + return imageView; + } + + public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) { + + Bitmap bm = null; + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, options); + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); + options.inJustDecodeBounds = false; + bm = BitmapFactory.decodeFile(path, options); + + return bm; + } + + public int calculateInSampleSize( + BitmapFactory.Options options, int reqWidth, int reqHeight) { + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + if (width > height) { + inSampleSize = Math.round((float)height / (float)reqHeight); + } else { + inSampleSize = Math.round((float)width / (float)reqWidth); + } + } + + return inSampleSize; + } +} diff --git a/app/src/main/java/com/example/newbody/LandmarkTriple.java b/app/src/main/java/com/example/newbody/LandmarkTriple.java new file mode 100644 index 0000000..f04cb0b --- /dev/null +++ b/app/src/main/java/com/example/newbody/LandmarkTriple.java @@ -0,0 +1,44 @@ +package com.example.newbody; + +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseLandmark; + +public class LandmarkTriple { + private final PoseLandmark firstLandmark; + private final PoseLandmark middleLandmark; + private final PoseLandmark lastLandmark; + + public LandmarkTriple(PoseLandmark firstLandmark, PoseLandmark middleLandmark, PoseLandmark lastLandmark) { + this.firstLandmark = firstLandmark; + this.middleLandmark = middleLandmark; + this.lastLandmark = lastLandmark; + } + + public PoseLandmark getFirstLandmark() { + return firstLandmark; + } + + public PoseLandmark getMiddleLandmark() { + return middleLandmark; + } + + public PoseLandmark getLastLandmark() { + return lastLandmark; + } + + public LandmarkTriple extractLandmark(Pose pose, TargetShape target) { + return new LandmarkTriple( + extractLandmarkFromType(pose, target.getFirstLandmarkType()), + extractLandmarkFromType(pose, target.getMiddleLandmarkType()), + extractLandmarkFromType(pose, target.getLastLandmarkType()) + ); + } + + public PoseLandmark extractLandmarkFromType(Pose pose, int landmarkType) { + return pose.getPoseLandmark(landmarkType); + } + + public boolean landmarkNotFound() { + return firstLandmark == null || middleLandmark == null || lastLandmark == null; + } +} diff --git a/app/src/main/java/com/example/newbody/LoadingActivity.java b/app/src/main/java/com/example/newbody/LoadingActivity.java new file mode 100644 index 0000000..03f6e04 --- /dev/null +++ b/app/src/main/java/com/example/newbody/LoadingActivity.java @@ -0,0 +1,29 @@ +package com.example.newbody; + +import android.app.Activity; +import android.os.Bundle; +import android.os.Handler; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; + +public class LoadingActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.background_loading); + ImageView walk = (ImageView) findViewById(R.id.gif_image); + Glide.with(this).load(R.drawable.walk).into(walk); + startLoading(); + } + private void startLoading() { + Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + finish(); + } + }, 3200); + } +} diff --git a/app/src/main/java/com/example/newbody/LoginActivity.java b/app/src/main/java/com/example/newbody/LoginActivity.java new file mode 100644 index 0000000..dc10e98 --- /dev/null +++ b/app/src/main/java/com/example/newbody/LoginActivity.java @@ -0,0 +1,176 @@ +package com.example.newbody; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.auth.SignInMethodQueryResult; + +public class LoginActivity extends AppCompatActivity { + private static final int RC_SIGN_IN = 9001; + EditText editEmail, editPassword; + FirebaseAuth mAuth; + View google; + private GoogleSignInClient mGoogleSignInClient; + private GoogleSignInAccount googleAccount; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login); + + mAuth = FirebaseAuth.getInstance(); + + View login = findViewById(R.id.login); + View manager = findViewById(R.id.button_manager); + Button register = (Button) findViewById(R.id.register); + + editEmail = findViewById(R.id.email); + editPassword = findViewById(R.id.password); + + // GoogleSignInClient 객체 초기화 + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(getString(R.string.default_web_client_id)) + .requestEmail() + .build(); + mGoogleSignInClient = GoogleSignIn.getClient(this, gso); + + google = findViewById(R.id.google); + + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(LoginActivity.this, LoadingActivity.class); + startActivity(intent); + + String emailS, passwordS; + emailS = String.valueOf(editEmail.getText()); + passwordS = String.valueOf(editPassword.getText()); + + if(TextUtils.isEmpty(emailS)){ + Toast.makeText(LoginActivity.this, "이메일을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if(TextUtils.isEmpty(passwordS)){ + Toast.makeText(LoginActivity.this, "비밀번호를 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + + mAuth.signInWithEmailAndPassword(emailS, passwordS) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } else { + Toast.makeText(LoginActivity.this, "로그인 실패", + Toast.LENGTH_SHORT).show(); + } + } + }); + + + } + }); + manager.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), ManagerLogin.class); + startActivity(intent); + finish(); + } + }); + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Membership.class); + startActivity(intent); + finish(); + } + }); + + google.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent signInIntent = mGoogleSignInClient.getSignInIntent(); + startActivityForResult(signInIntent, RC_SIGN_IN); + } + }); + } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + // GoogleSignInClient.getSignInIntent(...)의 결과 처리 + if (requestCode == RC_SIGN_IN) { + Task task = GoogleSignIn.getSignedInAccountFromIntent(data); + try { + // Google Sign In이 성공했을 경우, Firebase에 인증 + googleAccount = task.getResult(ApiException.class); + firebaseAuthWithGoogle(googleAccount.getIdToken()); + } catch (ApiException e) { + // Google Sign In 실패 + Toast.makeText(LoginActivity.this, "로그인 실패", Toast.LENGTH_SHORT).show(); + } + } + } + // Google 로그인 토큰을 이용하여 Firebase에 인증 + private void firebaseAuthWithGoogle(String idToken) { + AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null); + + mAuth.fetchSignInMethodsForEmail(googleAccount.getEmail()) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + SignInMethodQueryResult result = task.getResult(); + if (result.getSignInMethods().size() > 0) { + // 사용자가 이미 존재: 로그인 진행 + mAuth.signInWithCredential(credential) + .addOnCompleteListener(LoginActivity.this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + FirebaseUser user = mAuth.getCurrentUser(); + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } else { + // 인증 실패 + Toast.makeText(LoginActivity.this, "로그인 실패", Toast.LENGTH_SHORT).show(); + } + } + }); + } else { + // 사용자가 존재하지 않음: 에러 메시지 출력 + Toast.makeText(LoginActivity.this, "로그인 실패", Toast.LENGTH_SHORT).show(); + } + } else { + // 이메일 확인 실패: 에러 메시지 출력 + Toast.makeText(LoginActivity.this, "로그인 실패", Toast.LENGTH_SHORT).show(); + } + } + }); + } + +} diff --git a/app/src/main/java/com/example/newbody/MainActivity.java b/app/src/main/java/com/example/newbody/MainActivity.java index ac581d3..8b01fd5 100644 --- a/app/src/main/java/com/example/newbody/MainActivity.java +++ b/app/src/main/java/com/example/newbody/MainActivity.java @@ -2,13 +2,52 @@ import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; +import android.view.View; + +import com.example.newbody.mainInfo.MainActivityA; public class MainActivity extends AppCompatActivity { + private static final String PREFS_NAME = "MyPrefsFile"; + private static final String FIRST_RUN_KEY = "firstRun"; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + + // SharedPreferences에서 "firstRun" 키의 값을 불러옴 + SharedPreferences preferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + boolean isFirstRun = preferences.getBoolean(FIRST_RUN_KEY, true); + + View button = findViewById(R.id.button); + + // 처음 실행되는 경우에만 실행 + if (isFirstRun) { + // SharedPreferences에 "firstRun" 값을 false로 저장하여 다음에 앱이 실행될 때는 이 부분이 실행되지 않도록 함 + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(FIRST_RUN_KEY, false); + editor.apply(); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), MainActivityA.class); + startActivity(intent); + finish(); + } + }); + }else{ + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + } + }); + } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/ManagerLogin.java b/app/src/main/java/com/example/newbody/ManagerLogin.java new file mode 100644 index 0000000..3afadce --- /dev/null +++ b/app/src/main/java/com/example/newbody/ManagerLogin.java @@ -0,0 +1,36 @@ +package com.example.newbody; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +public class ManagerLogin extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_manager_login); + + View login = findViewById(R.id.managerLogin); + EditText password = findViewById(R.id.managerPassword); + + String passwordManager = "1234"; + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(password.getText().toString().equals(passwordManager)){ + Intent intent = new Intent(getApplicationContext(), ManagerMenu.class); + startActivity(intent); + finish(); + }else{ + Toast.makeText(ManagerLogin.this, "로그인 실패", Toast.LENGTH_SHORT).show(); + return; + } + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/ManagerMember.java b/app/src/main/java/com/example/newbody/ManagerMember.java new file mode 100644 index 0000000..7dca5a1 --- /dev/null +++ b/app/src/main/java/com/example/newbody/ManagerMember.java @@ -0,0 +1,236 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class ManagerMember extends AppCompatActivity { + + private CheckBox entire, free, money; + private Button prev, search; + private View memberLayout; + + private RecyclerView memberRecyclerView; + private MemberAdaptor adapter; + private FirebaseFirestore db; + private FirebaseUser user; + private List memberList = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_manager_member); + + prev = findViewById(R.id.prevButtonMemberManage); + memberLayout = findViewById(R.id.layout_member); + entire = findViewById(R.id.entire); + free = findViewById(R.id.freeMember); + money = findViewById(R.id.moneyMember); + search = findViewById(R.id.searchMember); + memberRecyclerView = findViewById(R.id.memberRecyclerView); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), ManagerMenu.class); + startActivity(intent); + finish(); + } + }); + + entire.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(entire.isChecked()){ + free.setChecked(true); + money.setChecked(true); + }else if(!entire.isChecked()){ + free.setChecked(false); + money.setChecked(false); + } + } + }); + + free.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(!free.isChecked()){ + entire.setChecked(false); + }else if(free.isChecked() && money.isChecked()){ + entire.setChecked(true); + } + } + }); + + money.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(!money.isChecked()){ + entire.setChecked(false); + }else if(free.isChecked() && money.isChecked()){ + entire.setChecked(true); + } + } + }); + + search.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + memberLayout.setVisibility(View.VISIBLE); + db = FirebaseFirestore.getInstance(); + memberRecyclerView.setLayoutManager(new LinearLayoutManager(ManagerMember.this)); + + fetchData(); + adapter = new MemberAdaptor(memberList); + memberRecyclerView.setAdapter(adapter); + } + }); + } + + private void fetchData() { + memberList.clear(); + + if(entire.isChecked()){ + db.collection("users").get().addOnCompleteListener(task -> { + if (task.isSuccessful()) { + QuerySnapshot querySnapshot = task.getResult(); + if (querySnapshot != null) { + for (QueryDocumentSnapshot document : querySnapshot) { + String name = document.getString("name"); + String birth = document.getString("birth"); + String gender = document.getString("gender"); + String grade = document.getString("grade"); + + if (name == null) name = "정보없음"; + if (birth == null) birth = "정보없음"; + if (gender == null) gender = "정보없음"; + if (grade == null) grade = "일반"; + + if(gender.equals("M") || gender.equals("남") || gender.equals("m") || + gender.equals("male") || gender.equals("xy") || gender.equals("man") || gender.equals("XY")){ + gender = "남자"; + }else if(gender.equals("W") || gender.equals("여") || gender.equals("w") || + gender.equals("female") || gender.equals("xx") || gender.equals("women") || gender.equals("XX")){ + gender = "여자"; + } + + if(!name.equals("정보없음") || !birth.equals("정보없음") || !gender.equals("정보없음")){ + memberList.add(new MemberItem(name, birth, gender, grade)); + } + } + adapter.notifyDataSetChanged(); + } + } else { + // 에러 처리 + Log.d("Firestore Error", "Error getting documents: ", task.getException()); + } + }); + }else if(money.isChecked() && !entire.isChecked()){ + db.collection("users").get().addOnCompleteListener(task -> { + if (task.isSuccessful()) { + QuerySnapshot querySnapshot = task.getResult(); + if (querySnapshot != null) { + for (QueryDocumentSnapshot document : querySnapshot) { + String name = document.getString("name"); + String birth = document.getString("birth"); + String gender = document.getString("gender"); + String grade = document.getString("grade"); + + if (name == null) name = "정보없음"; + if (birth == null) birth = "정보없음"; + if (gender == null) gender = "정보없음"; + if (grade == null) grade = "일반"; + + if(gender.equals("M") || gender.equals("남") || gender.equals("m") || + gender.equals("male") || gender.equals("xy") || gender.equals("man") || gender.equals("XY")){ + gender = "남자"; + }else if(gender.equals("W") || gender.equals("여") || gender.equals("w") || + gender.equals("female") || gender.equals("xx") || gender.equals("women") || gender.equals("XX")){ + gender = "여자"; + } + + if(grade.equals("프리미엄") && (!name.equals("정보없음") || !birth.equals("정보없음") || !gender.equals("정보없음"))){ + memberList.add(new MemberItem(name, birth, gender, grade)); + } + } + adapter.notifyDataSetChanged(); + } + } else { + // 에러 처리 + Log.d("Firestore Error", "Error getting documents: ", task.getException()); + } + }); + }else if(free.isChecked() && !entire.isChecked()){ + db.collection("users").get().addOnCompleteListener(task -> { + if (task.isSuccessful()) { + QuerySnapshot querySnapshot = task.getResult(); + if (querySnapshot != null) { + for (QueryDocumentSnapshot document : querySnapshot) { + String name = document.getString("name"); + String birth = document.getString("birth"); + String gender = document.getString("gender"); + String grade = document.getString("grade"); + + if (name == null) name = "정보없음"; + if (birth == null) birth = "정보없음"; + if (gender == null) gender = "정보없음"; + if (grade == null) grade = "일반"; + + if(gender.equals("M") || gender.equals("남") || gender.equals("m") || + gender.equals("male") || gender.equals("xy") || gender.equals("man") || gender.equals("XY")){ + gender = "남자"; + }else if(gender.equals("W") || gender.equals("여") || gender.equals("w") || + gender.equals("female") || gender.equals("xx") || gender.equals("women") || gender.equals("XX")){ + gender = "여자"; + } + + if(grade.equals("일반") && (!name.equals("정보없음") || !birth.equals("정보없음") || !gender.equals("정보없음"))){ + memberList.add(new MemberItem(name, birth, gender, grade)); + } + } + adapter.notifyDataSetChanged(); + } + } else { + // 에러 처리 + Log.d("Firestore Error", "Error getting documents: ", task.getException()); + } + }); + } + } + + static class MemberItem { + String name; + String birth; + String gender; + String grade; + + public MemberItem(String name, String birth, String gender, String grade) { + this.name = name; + this.birth = birth; + this.gender = gender; + this.grade = grade; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/ManagerMenu.java b/app/src/main/java/com/example/newbody/ManagerMenu.java new file mode 100644 index 0000000..362c911 --- /dev/null +++ b/app/src/main/java/com/example/newbody/ManagerMenu.java @@ -0,0 +1,52 @@ +package com.example.newbody; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.Toast; + +public class ManagerMenu extends AppCompatActivity { + + private View member, money; + private Button logout; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_manager_menu); + + member = findViewById(R.id.memberManage); + money = findViewById(R.id.moneyManage); + logout = findViewById(R.id.logout); + + member.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), ManagerMember.class); + startActivity(intent); + finish(); + } + }); + + money.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), ManagerMoney.class); + startActivity(intent); + finish(); + } + }); + + logout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), MainActivity.class); + startActivity(intent); + finish(); + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/ManagerMoney.java b/app/src/main/java/com/example/newbody/ManagerMoney.java new file mode 100644 index 0000000..7b1d969 --- /dev/null +++ b/app/src/main/java/com/example/newbody/ManagerMoney.java @@ -0,0 +1,373 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.DialogFragment; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.NumberPicker; +import android.widget.TextView; +import android.widget.Toast; + +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.data.LineDataSet; +import com.github.mikephil.charting.formatter.IAxisValueFormatter; +import com.github.mikephil.charting.formatter.ValueFormatter; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +public class ManagerMoney extends AppCompatActivity implements OnDateSetListener{ + + private Button exerciseRange, graphView, prev, selectCalendar; + private String select_range; + private FirebaseFirestore db; + private FirebaseUser user; + private LineChart chart, chart2; + private TextView dateSelect; + private View dateView; + SimpleDateFormat yy, mm; + Date date; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_manager_money); + + initView(); + + exerciseRange.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showRangeDialog(); + } + }); + + graphView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(exerciseRange.getText().equals("범위")){ + Toast.makeText(ManagerMoney.this, "범위를 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(exerciseRange.getText().equals("월별 통계")){ + int yearNum = Integer.parseInt(yy.format(date)); + int mmNum = Integer.parseInt(mm.format(date)); + dateView.setVisibility(View.VISIBLE); + chart.setVisibility(View.GONE); + chart2.setVisibility(View.VISIBLE); + dateSelect.setText(yearNum + "년 " + mmNum + "월 "); + fetchMonthlyData(yearNum, mmNum); + }else if(exerciseRange.getText().equals("최근 7일")){ + chart.setVisibility(View.VISIBLE); + chart2.setVisibility(View.GONE); + dateView.setVisibility(View.INVISIBLE); + fetchLast7DaysData(); + } + } + }); + + selectCalendar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showDatePickerDialog(view); + } + }); + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), ManagerMenu.class); + startActivity(intent); + finish(); + } + }); + + } + + public void initView(){ + prev = findViewById(R.id.prevButtonMoneyManage); + exerciseRange = findViewById(R.id.graphRange2); + graphView = findViewById(R.id.graph_money_button); + selectCalendar = findViewById(R.id.selectDate1); + db = FirebaseFirestore.getInstance(); + user = FirebaseAuth.getInstance().getCurrentUser(); + chart = findViewById(R.id.chart11); + chart2 = findViewById(R.id.chart22); + dateSelect = findViewById(R.id.calendarText1); + dateView = findViewById(R.id.calendarSelect1); + date = new Date(); + yy = new SimpleDateFormat("yyyy"); + mm = new SimpleDateFormat("MM"); + } + + @Override + public void onDateSet(int year, int month) { + dateSelect.setText(year + "년 " + (month + 1) + "월"); + } + + private void showRangeDialog() { + final String[] exOptions = {"월별 통계", "최근 7일"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("범위 선택"); + builder.setItems(exOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_range = exOptions[which]; + exerciseRange.setText(select_range); + } + }); + builder.show(); + } + + // 새로운 클래스 + public class SalesData { + public String date; + public int sales; + + public SalesData(String date, int sales) { + this.date = date; + this.sales = sales; + } + } + + public void fetchLast7DaysData() { + final String collectionName = "payments"; + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.getDefault()); + final ArrayList last7Days = new ArrayList<>(); + final ArrayList salesDataList = new ArrayList<>(); + + // Generate the last 7 days in yyyyMMdd format + Calendar cal = Calendar.getInstance(); + for (int i = 0; i < 7; i++) { + last7Days.add(sdf.format(cal.getTime())); + cal.add(Calendar.DATE, -1); + } + + for (final String date : last7Days) { + DocumentReference paymentRecordRef = db.collection(collectionName).document(date); + paymentRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + int amount = document.exists() ? document.getLong("amount").intValue() : 0; + + salesDataList.add(new SalesData(date, amount)); + + if (salesDataList.size() == 7) { + // 날짜로 정렬 + Collections.sort(salesDataList, (a, b) -> a.date.compareTo(b.date)); + + // 날짜와 매출 데이터를 분리 + ArrayList sortedDates = new ArrayList<>(); + ArrayList sortedSales = new ArrayList<>(); + for (SalesData data : salesDataList) { + sortedDates.add(data.date); + sortedSales.add(data.sales); + } + plotGraph(sortedSales, sortedDates); + } + } + } + }); + } + } + + private void plotGraph(ArrayList salesData, ArrayList last7Days) { + ArrayList entries = new ArrayList<>(); + for (int i = 0; i < salesData.size(); i++) { + entries.add(new Entry(i, salesData.get(i))); + } + + LineDataSet dataSet = new LineDataSet(entries, " 그래프"); + + dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); + dataSet.setLineWidth(2f); + dataSet.setColor(Color.parseColor("#9DCEFF")); + dataSet.setCircleColor(Color.parseColor("#9DCEFF")); + + LineData lineData = new LineData(dataSet); + + chart.getXAxis().setValueFormatter(new ValueFormatter() { + @Override + public String getFormattedValue(float value) { + if (value >= 0 && value < last7Days.size()) { + return last7Days.get((int) value).substring(4, 8); + } + return ""; + } + }); + + chart.getAxisRight().setEnabled(false); + + chart.setData(lineData); + chart.invalidate(); + } + + // 월별 매출 데이터를 가져오는 메서드 + public void fetchMonthlyData(int year, int month) { + final String collectionName = "payments"; + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.getDefault()); + final ArrayList salesDataList = new ArrayList<>(); + final ArrayList daysInMonth = new ArrayList<>(); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, month - 1); // Calendar.MONTH is zero-based + cal.set(Calendar.DAY_OF_MONTH, 1); + + int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); + for (int i = 1; i <= maxDay; i++) { + cal.set(Calendar.DAY_OF_MONTH, i); + daysInMonth.add(sdf.format(cal.getTime())); + } + + for (final String date : daysInMonth) { + DocumentReference paymentRecordRef = db.collection(collectionName).document(date); + paymentRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + int amount = document.exists() ? document.getLong("amount").intValue() : 0; + salesDataList.add(new SalesData(date, amount)); + + if (salesDataList.size() == maxDay) { + Collections.sort(salesDataList, (a, b) -> a.date.compareTo(b.date)); + ArrayList sortedDates = new ArrayList<>(); + ArrayList sortedSales = new ArrayList<>(); + for (SalesData data : salesDataList) { + sortedDates.add(data.date); + sortedSales.add(data.sales); + } + plotMonthGraph(sortedSales, sortedDates); + } + } + } + }); + } + } + + private void plotMonthGraph(ArrayList salesData, ArrayList last7Days) { + ArrayList entries = new ArrayList<>(); + for (int i = 0; i < salesData.size(); i++) { + entries.add(new Entry(i, salesData.get(i))); + } + + LineDataSet dataSet = new LineDataSet(entries, " 그래프"); + + dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); + dataSet.setLineWidth(2f); + dataSet.setColor(Color.parseColor("#9DCEFF")); + dataSet.setCircleColor(Color.parseColor("#9DCEFF")); + + LineData lineData = new LineData(dataSet); + + chart2.getXAxis().setValueFormatter(new ValueFormatter() { + @Override + public String getFormattedValue(float value) { + if (value >= 0 && value < last7Days.size()) { + return last7Days.get((int) value).substring(4, 8); + } + return ""; + } + }); + + chart2.getAxisRight().setEnabled(false); + + chart2.setData(lineData); + chart2.invalidate(); + // 한 화면에 7개의 데이터 포인트만 보이도록 설정 + chart2.setVisibleXRangeMaximum(7); + // 최초로 마지막 7개의 데이터 포인트를 보여줌 + chart2.moveViewToX(0); + } + + public void showDatePickerDialog(View v) { + Graph.YearMonthPickerDialog dialog = new Graph.YearMonthPickerDialog(); + dialog.setListener(new OnDateSetListener() { + @Override + public void onDateSet(int year, int month) { + // 여기에 로직 추가 + dateSelect.setText(year + "년 " + month + "월"); + fetchMonthlyData(year, month); + } + }); + dialog.show(getSupportFragmentManager(), "YearMonthPickerDialog"); + + } + + public static class YearMonthPickerDialog extends DialogFragment { + private static final int MAX_YEAR = 2099; + private static final int MIN_YEAR = 2000; + + private OnDateSetListener listener; + + public void setListener(OnDateSetListener listener) { + this.listener = listener; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + + View dialog = inflater.inflate(R.layout.year_month_picker, null); + final NumberPicker monthPicker = dialog.findViewById(R.id.monthPicker); + final NumberPicker yearPicker = dialog.findViewById(R.id.yearPicker); + + monthPicker.setMinValue(1); + monthPicker.setMaxValue(12); + monthPicker.setValue(1); + + int year = Calendar.getInstance().get(Calendar.YEAR); + yearPicker.setMinValue(MIN_YEAR); + yearPicker.setMaxValue(MAX_YEAR); + yearPicker.setValue(year); + + builder.setView(dialog) + .setPositiveButton("확인", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + if (listener != null) { + listener.onDateSet(yearPicker.getValue(), monthPicker.getValue()); + } + } + }) + .setNegativeButton("취소", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + YearMonthPickerDialog.this.getDialog().cancel(); + } + }); + return builder.create(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/MemberAdaptor.java b/app/src/main/java/com/example/newbody/MemberAdaptor.java new file mode 100644 index 0000000..c6f7cfd --- /dev/null +++ b/app/src/main/java/com/example/newbody/MemberAdaptor.java @@ -0,0 +1,60 @@ +package com.example.newbody; + +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +public class MemberAdaptor extends RecyclerView.Adapter{ + private List memberList; + + public MemberAdaptor(List memberList) { + this.memberList = memberList; + } + + @NonNull + @Override + public MemberViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.member_item, parent, false); + return new MemberViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull MemberViewHolder holder, int position) { + ManagerMember.MemberItem currentItem = memberList.get(position); + holder.nameTextView.setText(currentItem.name); + holder.birthTextView.setText(currentItem.birth); + holder.genderTextView.setText(currentItem.gender); + holder.gradeTextView.setText(currentItem.grade); + if(currentItem.grade.equals("프리미엄")){ + holder.gradeTextView.setTextColor(Color.parseColor("#ffcc00")); + } + } + + @Override + public int getItemCount() { + return memberList.size(); + } + + static class MemberViewHolder extends RecyclerView.ViewHolder { + TextView nameTextView; + TextView birthTextView; + TextView genderTextView; + TextView gradeTextView; + + public MemberViewHolder(@NonNull View itemView) { + super(itemView); + nameTextView = itemView.findViewById(R.id.nameTextView); + birthTextView = itemView.findViewById(R.id.birthTextView); + genderTextView = itemView.findViewById(R.id.genderTextView); + gradeTextView = itemView.findViewById(R.id.gradeTextView); + } + } +} diff --git a/app/src/main/java/com/example/newbody/MemberChangeActivity.java b/app/src/main/java/com/example/newbody/MemberChangeActivity.java new file mode 100644 index 0000000..b7316fe --- /dev/null +++ b/app/src/main/java/com/example/newbody/MemberChangeActivity.java @@ -0,0 +1,296 @@ +package com.example.newbody; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.bumptech.glide.Glide; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.annotations.Nullable; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; +import com.google.firebase.storage.UploadTask; + +import java.util.HashMap; +import java.util.Map; + +public class MemberChangeActivity extends AppCompatActivity { + + private static final int PICK_IMAGE_REQUEST = 1; + private Uri imageUri; + private StorageReference storageRef; + + private FirebaseFirestore db; + private FirebaseAuth mAuth; + private EditText nameEditText, genderEditText, birthEditText, weightEditText, heightEditText; + + private FirebaseUser user; + private Button prev; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_member_change); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + user = mAuth.getCurrentUser(); + + nameEditText = findViewById(R.id.name_fix); + genderEditText = findViewById(R.id.gender_fix); + birthEditText = findViewById(R.id.birth_fix); + weightEditText = findViewById(R.id.weight_fix); + heightEditText = findViewById(R.id.height_fix); + + View updateButton = findViewById(R.id.fix_button); + View imageButton = findViewById(R.id.pic_button); + prev = findViewById(R.id.prevButtonfix); + + storageRef = FirebaseStorage.getInstance().getReference("profile_pics"); + + loadImageFromFirestore(); + + if(user == null){ + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @SuppressLint("SetTextI18n") + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + birthEditText.setText(document.getString("birth")); + genderEditText.setText(document.getString("gender")); + nameEditText.setText(document.getString("name")); + weightEditText.setText(document.getString("weight")); + heightEditText.setText(document.getString("height")); + } + } else { + } + } + }); + } + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + + imageButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + openFileChooser(); + } + }); + + updateButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (imageUri != null) { + uploadFile(); + } + + String name = nameEditText.getText().toString(); + String gender = genderEditText.getText().toString(); + String birth = birthEditText.getText().toString(); + String weight = weightEditText.getText().toString(); + String height = heightEditText.getText().toString(); + + if (TextUtils.isEmpty(name)) { + Toast.makeText(MemberChangeActivity.this, "이름을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(gender)) { + Toast.makeText(MemberChangeActivity.this, "성별을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(birth)) { + Toast.makeText(MemberChangeActivity.this, "생일을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(weight)) { + Toast.makeText(MemberChangeActivity.this, "몸무게를 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(height)) { + Toast.makeText(MemberChangeActivity.this, "키를 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + + Map userData = new HashMap<>(); + if (user != null) { + userData.put("name", name); + userData.put("gender", gender); + userData.put("birth", birth); + userData.put("weight", weight); + userData.put("height", height); + } + + db.collection("users").document(user.getUid()) + .update(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + }); + } + + private void openFileChooser() { + Intent intent = new Intent(); + intent.setType("image/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + startActivityForResult(intent, PICK_IMAGE_REQUEST); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) { + imageUri = data.getData(); + + ImageView selectedImageView = findViewById(R.id.profile_pic); + Glide.with(this).load(imageUri).into(selectedImageView); + } + } + + private void uploadFile() { + final StorageReference oldFileReference = storageRef.child(mAuth.getCurrentUser().getUid() + ".jpg"); + oldFileReference.delete().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + // After deleting the old image, upload the new one + final StorageReference fileReference = storageRef.child(mAuth.getCurrentUser().getUid() + ".jpg"); + fileReference.putFile(imageUri) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { + fileReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Uri uri) { + String downloadUrl = uri.toString(); + updateImageUrlToFirestore(downloadUrl); + } + }); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + }).addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + // If the old image doesn't exist, just upload the new one + final StorageReference fileReference = storageRef.child(mAuth.getCurrentUser().getUid() + ".jpg"); + fileReference.putFile(imageUri) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { + fileReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Uri uri) { + String downloadUrl = uri.toString(); + updateImageUrlToFirestore(downloadUrl); + } + }); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + }); + } + + private void updateImageUrlToFirestore(String url) { + Map data = new HashMap<>(); + data.put("imageUrl", url); + + db.collection("users").document(mAuth.getCurrentUser().getUid()) + .update(data) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + + private void loadImageFromFirestore() { + db.collection("users").document(mAuth.getCurrentUser().getUid()) + .get() + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(DocumentSnapshot documentSnapshot) { + if (documentSnapshot.exists()) { + String imageUrl = documentSnapshot.getString("imageUrl"); + if (!TextUtils.isEmpty(imageUrl)) { + loadImageIntoImageView(imageUrl); + } else { + } + } else { + } + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + + private void loadImageIntoImageView(String imageUrl) { + ImageView userImageView = findViewById(R.id.profile_pic); + + Glide.with(this) + .load(imageUrl) + .circleCrop() + .into(userImageView); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/MemberInfo.java b/app/src/main/java/com/example/newbody/MemberInfo.java new file mode 100644 index 0000000..64c0f29 --- /dev/null +++ b/app/src/main/java/com/example/newbody/MemberInfo.java @@ -0,0 +1,223 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; + +import java.util.ArrayList; + +public class MemberInfo extends AppCompatActivity { + + Button prev; + TextView name, gender, birth, weight, height; + ImageView profile; + + private FirebaseFirestore db; + private FirebaseAuth mAuth; + private Uri imageUri; + private StorageReference storageRef; + private FirebaseUser user; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_member_info); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + initViews(); + + storageRef = FirebaseStorage.getInstance().getReference("profile_pics"); + loadImageFromFirestore(); + + if(user == null){ + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + }else { + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @SuppressLint("SetTextI18n") + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String date = document.getString("birth"); + int year = Integer.parseInt(date.substring(0, 4)); + int mm = Integer.parseInt(date.substring(4, 6)); + int dd = Integer.parseInt(date.substring(6, 8)); + + if(document.getString("gender").equals("M") || document.getString("gender").equals("m")){ + gender.setText("남자"); + }else if(document.getString("gender").equals("W") || document.getString("gender").equals("w")){ + gender.setText("여자"); + }else{ + gender.setText(document.getString("gender")); + } + birth.setText(year + "년 " + mm + "월 " + dd + "일"); + name.setText(document.getString("name") + "님"); + weight.setText(document.getString("weight")+"kg"); + height.setText(document.getString("height")+"cm"); + } + } else { + } + } + }); + } + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + + } + + public void initViews(){ + prev = findViewById(R.id.prevButtonInfo); + name = findViewById(R.id.name_info); + gender = findViewById(R.id.gender_info); + birth = findViewById(R.id.birth_info); + weight = findViewById(R.id.weight_info); + height = findViewById(R.id.height_info); + profile = findViewById(R.id.profile_pic_info); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + user = mAuth.getCurrentUser(); + } + + private void loadImageFromFirestore() { + db.collection("users").document(mAuth.getCurrentUser().getUid()) + .get() + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(DocumentSnapshot documentSnapshot) { + if (documentSnapshot.exists()) { + String imageUrl = documentSnapshot.getString("imageUrl"); + if (!TextUtils.isEmpty(imageUrl)) { + loadImageIntoImageView(imageUrl); + } else { + } + } else { + } + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + + private void loadImageIntoImageView(String imageUrl) { + + Glide.with(this) + .load(imageUrl) + .circleCrop() + .into(profile); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Membership.java b/app/src/main/java/com/example/newbody/Membership.java new file mode 100644 index 0000000..c9a6480 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership.java @@ -0,0 +1,199 @@ +package com.example.newbody; + +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.android.material.textfield.TextInputEditText; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.firestore.FirebaseFirestore; + +import java.util.HashMap; +import java.util.Map; + +public class Membership extends AppCompatActivity { + private static final int RC_SIGN_IN = 9001; + EditText email, password, passwordCheck; + TextView check_text; + private boolean passwordCheckCheck = false; + View google; + private FirebaseAuth mAuth; + private FirebaseFirestore db; + + private GoogleSignInClient mGoogleSignInClient; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership); + + View register = findViewById(R.id.register); + Button login = findViewById(R.id.login); + + google = findViewById(R.id.google); + + mAuth = FirebaseAuth.getInstance(); + db = FirebaseFirestore.getInstance(); + + email = findViewById(R.id.email); + password = findViewById(R.id.password); + passwordCheck = findViewById(R.id.passwordCheck); + check_text = findViewById(R.id.check_text); + + // GoogleSignInClient 객체 초기화 + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(getString(R.string.default_web_client_id)) + .requestEmail() + .build(); + mGoogleSignInClient = GoogleSignIn.getClient(this, gso); + + passwordCheck.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + if(password.getText().toString().equals(passwordCheck.getText().toString())) { + passwordCheckCheck = true; + check_text.setText("비밀번호와 일치합니다. "); + check_text.setTextColor(Color.parseColor("#00cc00")); + } else { + passwordCheckCheck = false; + check_text.setText("비밀번호를 확인해주세요. "); + check_text.setTextColor(Color.parseColor("#ff3300")); + } + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + String emailS, passwordS, passwordCheckS; + emailS = String.valueOf(email.getText()); + passwordS = String.valueOf(password.getText()); + passwordCheckS = String.valueOf(passwordCheck.getText()); + + if(TextUtils.isEmpty(emailS)){ + Toast.makeText(Membership.this, "이메일을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if(TextUtils.isEmpty(passwordS)){ + Toast.makeText(Membership.this, "비밀번호를 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if(TextUtils.isEmpty(passwordCheckS)){ + Toast.makeText(Membership.this, "비밀번호를 확인하세요", Toast.LENGTH_SHORT).show(); + return; + } + + if(passwordCheckCheck == true){ + // Firebase Authentication을 이용하여 사용자를 생성합니다. + mAuth.createUserWithEmailAndPassword(emailS, passwordS) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Intent intent = new Intent(getApplicationContext(), Membership1.class); + startActivity(intent); + finish(); + } else { + Toast.makeText(Membership.this, "회원가입 실패.", Toast.LENGTH_SHORT).show(); + } + } + }); + }else{ + Toast.makeText(Membership.this, "비밀번호를 확인하세요", Toast.LENGTH_SHORT).show(); + return; + } + + } + }); + + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + finish(); + } + }); + + google.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent signInIntent = mGoogleSignInClient.getSignInIntent(); + startActivityForResult(signInIntent, RC_SIGN_IN); + } + }); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + // GoogleSignInClient.getSignInIntent(...)의 결과 처리 + if (requestCode == RC_SIGN_IN) { + Task task = GoogleSignIn.getSignedInAccountFromIntent(data); + try { + // Google Sign In이 성공했을 경우, Firebase에 인증 + GoogleSignInAccount account = task.getResult(ApiException.class); + firebaseAuthWithGoogle(account.getIdToken()); + } catch (ApiException e) { + // Google Sign In 실패 + Toast.makeText(Membership.this, "회원가입 실패", Toast.LENGTH_SHORT).show(); + } + } + } + + // Google 로그인 토큰을 이용하여 Firebase에 인증 + private void firebaseAuthWithGoogle(String idToken) { + AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null); + mAuth.signInWithCredential(credential) + .addOnCompleteListener(this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + FirebaseUser user = mAuth.getCurrentUser(); + Intent intent = new Intent(getApplicationContext(), Membership1.class); + startActivity(intent); + finish(); + } else { + // 인증 실패 + Toast.makeText(Membership.this, "회원가입 실패", Toast.LENGTH_SHORT).show(); + } + } + }); + } +} diff --git a/app/src/main/java/com/example/newbody/Membership1.java b/app/src/main/java/com/example/newbody/Membership1.java new file mode 100644 index 0000000..bd93bc2 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership1.java @@ -0,0 +1,29 @@ +package com.example.newbody; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +public class Membership1 extends AppCompatActivity { + + View next; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership1); + + next = findViewById(R.id.buttonNext01); + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Membership2.class); + startActivity(intent); + finish(); + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Membership2.java b/app/src/main/java/com/example/newbody/Membership2.java new file mode 100644 index 0000000..337b436 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership2.java @@ -0,0 +1,108 @@ +package com.example.newbody; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.messaging.FirebaseMessaging; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.HashMap; +import java.util.Map; + +public class Membership2 extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership2); + + View register = findViewById(R.id.button); + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + String name = ((EditText) findViewById(R.id.username)).getText().toString(); + String gender = ((EditText) findViewById(R.id.sex)).getText().toString(); + String birth = ((EditText) findViewById(R.id.birth)).getText().toString(); + String weight = ((EditText) findViewById(R.id.weight)).getText().toString(); + String height = ((EditText) findViewById(R.id.height)).getText().toString(); + + if (TextUtils.isEmpty(name)) { + Toast.makeText(Membership2.this, "이름을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(gender)) { + Toast.makeText(Membership2.this, "성별을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(birth)) { + Toast.makeText(Membership2.this, "생일을 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(weight)) { + Toast.makeText(Membership2.this, "몸무게를 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(height)) { + Toast.makeText(Membership2.this, "키를 입력하세요", Toast.LENGTH_SHORT).show(); + return; + } + + FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> { + if (!task.isSuccessful()) { + return; + } + String token = task.getResult(); + + FirebaseUser user = mAuth.getCurrentUser(); + Map userData = new HashMap<>(); + if (user != null) { + userData.put("name", name); + userData.put("gender", gender); + userData.put("birth", birth); + userData.put("weight", weight); + userData.put("height", height); + userData.put("fcmToken", token); // 토큰 값을 저장합니다. + userData.put("uid", user.getUid()); + db.collection("users").document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Intent intent = new Intent(getApplicationContext(), Membership4.class); + startActivity(intent); + finish(); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + }); + + } + }); + + } +} diff --git a/app/src/main/java/com/example/newbody/Membership3.java b/app/src/main/java/com/example/newbody/Membership3.java new file mode 100644 index 0000000..484ae19 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership3.java @@ -0,0 +1,28 @@ +package com.example.newbody; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +public class Membership3 extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership3); + Intent intent = new Intent(this, LoadingActivity.class); + startActivity(intent); + + View register = findViewById(R.id.button); + + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + finish(); + } + }); + } +} diff --git a/app/src/main/java/com/example/newbody/Membership4.java b/app/src/main/java/com/example/newbody/Membership4.java new file mode 100644 index 0000000..4069b05 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership4.java @@ -0,0 +1,202 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.os.Bundle; +import android.telephony.SmsManager; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import android.Manifest; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthProvider; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class Membership4 extends AppCompatActivity { + + EditText inputPhoneNum, inputCheckNum; + TextView time, check; + Button sendSMSBtn, checkBtn; + String checkNum; + private boolean checkNext = false; + static final int SMS_SEND_PERMISSION = 1; + + SharedPreferences pref; + SharedPreferences.Editor editor; + private FirebaseAuth mAuth; + private FirebaseFirestore db; + private FirebaseUser user; + private String verificationId; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership4); + + mAuth = FirebaseAuth.getInstance(); + db = FirebaseFirestore.getInstance(); + user = mAuth.getCurrentUser(); + + pref = getPreferences(MODE_PRIVATE); + editor = pref.edit(); + + inputPhoneNum = findViewById(R.id.input_phone_num); + sendSMSBtn = findViewById(R.id.send_sms_button); + inputCheckNum = findViewById(R.id.input_check_num); + checkBtn = findViewById(R.id.check_button); + time = findViewById(R.id.timeText); + check = findViewById(R.id.checkPhoneNum); + View register = findViewById(R.id.button); + + int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS); + if(permissionCheck != PackageManager.PERMISSION_GRANTED){ + if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS)){ + Toast.makeText(this, "SMS 권한이 필요합니다. ", Toast.LENGTH_SHORT).show(); + } + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.SEND_SMS}, SMS_SEND_PERMISSION); + } + + sendSMSBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + String num = "+82 " + inputPhoneNum.getText().toString().substring(1); + startPhoneNumberVerification(num); + } + }); + + checkBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + verifyPhoneNumberWithCode(verificationId, inputCheckNum.getText().toString()); + } + }); + + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(checkNext){ + savePhoneNumber(user); + + Intent intent = new Intent(getApplicationContext(), Membership5.class); + intent.putExtra("uid", user.getUid()); + startActivity(intent); + finish(); + }else{ + Toast.makeText(Membership4.this, "전화번호 인증을 해주세요", Toast.LENGTH_SHORT).show(); + } + } + }); + } + + private void startPhoneNumberVerification(String phoneNumber) { + PhoneAuthProvider.getInstance().verifyPhoneNumber( + phoneNumber, + 60, + TimeUnit.SECONDS, + this, + new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onVerificationCompleted(PhoneAuthCredential credential) { + signInWithPhoneAuthCredential(credential); + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(Membership4.this, "인증 불가" + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onCodeSent(String verId, PhoneAuthProvider.ForceResendingToken token) { + verificationId = verId; + Toast.makeText(Membership4.this, "인증번호가 발송되었습니다. ", Toast.LENGTH_SHORT).show(); + time.setVisibility(View.VISIBLE); + } + } + ); + } + + private void verifyPhoneNumberWithCode(String verificationId, String code) { + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code); + signInWithPhoneAuthCredential(credential); + } + + private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(this, task -> { + if (task.isSuccessful()) { + FirebaseUser user = task.getResult().getUser(); + check.setText("인증이 완료되었습니다. "); + check.setTextColor(Color.parseColor("#00cc00")); + checkNext = true; + } else { + check.setText("인증번호가 일치하지 않습니다. "); + check.setTextColor(Color.parseColor("#ff3300")); + } + }); + } + + private void savePhoneNumber(FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "users"; + userData.put("phone", inputPhoneNum.getText().toString()); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Membership5.java b/app/src/main/java/com/example/newbody/Membership5.java new file mode 100644 index 0000000..9f88f11 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership5.java @@ -0,0 +1,123 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; + +import java.util.HashMap; +import java.util.Map; + +public class Membership5 extends AppCompatActivity { + + private FirebaseAuth mAuth; + private FirebaseFirestore db; + private FirebaseUser user; + private TextView pre1, pre2; + private RadioButton radioButton1, radioButton2; + private String userUid; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership5); + + mAuth = FirebaseAuth.getInstance(); + db = FirebaseFirestore.getInstance(); + user = mAuth.getCurrentUser(); + + View register = findViewById(R.id.button); + radioButton1 = findViewById(R.id.radioButton1); + radioButton2 = findViewById(R.id.radioButton2); + pre1 = findViewById(R.id.pre1); + pre2 = findViewById(R.id.pre2); + + Intent intent = getIntent(); + userUid = intent.getStringExtra("uid"); + + final String[] selectEx = new String[1]; + + radioButton1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (((RadioButton) v).isChecked()) { + radioButton2.setChecked(false); + selectEx[0] = pre1.getText().toString(); + } + } + }); + + radioButton2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (((RadioButton) v).isChecked()) { + radioButton1.setChecked(false); + selectEx[0] = pre2.getText().toString(); + } + } + }); + + + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(!radioButton1.isChecked() && !radioButton2.isChecked()){ + Toast.makeText(Membership5.this, "선호하는 운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + savePreference(selectEx[0], user); + Intent intent = new Intent(getApplicationContext(), Membership6.class); + intent.putExtra("uid", userUid); + startActivity(intent); + finish(); + } + }); + } + + private void savePreference(String selectEx, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "users"; + userData.put("preference1", selectEx); + + DocumentReference userRecordRef = db.collection(collectionName).document(userUid); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Membership6.java b/app/src/main/java/com/example/newbody/Membership6.java new file mode 100644 index 0000000..97bb4e7 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Membership6.java @@ -0,0 +1,137 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; + +import java.util.HashMap; +import java.util.Map; + +public class Membership6 extends AppCompatActivity { + + private FirebaseAuth mAuth; + private FirebaseFirestore db; + private FirebaseUser user; + private TextView pre1, pre2, pre3; + private RadioButton radioButton1, radioButton2, radioButton3; + private String userUid; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_membership6); + + mAuth = FirebaseAuth.getInstance(); + db = FirebaseFirestore.getInstance(); + user = mAuth.getCurrentUser(); + + View register = findViewById(R.id.button); + radioButton1 = findViewById(R.id.radioButton1); + radioButton2 = findViewById(R.id.radioButton2); + radioButton3 = findViewById(R.id.radioButton3); + pre1 = findViewById(R.id.ex1); + pre2 = findViewById(R.id.ex2); + pre3 = findViewById(R.id.ex3); + + Intent intent = getIntent(); + userUid = intent.getStringExtra("uid"); + + final String[] selectEx = new String[1]; + + radioButton1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (((RadioButton) v).isChecked()) { + radioButton2.setChecked(false); + radioButton3.setChecked(false); + selectEx[0] = pre1.getText().toString(); + } + } + }); + + radioButton2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (((RadioButton) v).isChecked()) { + radioButton1.setChecked(false); + radioButton3.setChecked(false); + selectEx[0] = pre2.getText().toString(); + } + } + }); + + radioButton3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (((RadioButton) v).isChecked()) { + radioButton1.setChecked(false); + radioButton2.setChecked(false); + selectEx[0] = pre3.getText().toString(); + } + } + }); + + + register.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(!radioButton1.isChecked() && !radioButton2.isChecked() && !radioButton3.isChecked()){ + Toast.makeText(Membership6.this, "선호하는 운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + savePreference(selectEx[0], user); + Intent intent = new Intent(getApplicationContext(), Membership3.class); + startActivity(intent); + finish(); + } + }); + } + + private void savePreference(String selectEx, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "users"; + userData.put("preference2", selectEx); + + DocumentReference userRecordRef = db.collection(collectionName).document(userUid); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Menu.java b/app/src/main/java/com/example/newbody/Menu.java new file mode 100644 index 0000000..3fc4560 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Menu.java @@ -0,0 +1,271 @@ +package com.example.newbody; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.MenuItem; +import android.widget.Toast; +import android.Manifest; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.google.android.material.bottomnavigation.BottomNavigationView; + +import java.util.ArrayList; + +public class Menu extends AppCompatActivity { + + private static final int PERMISSIONS_REQUEST_RECORD_AUDIO = 1; + + private BottomNavigationView bottomNavigationView; + private FragmentManager fm; + private FragmentTransaction ft; + private Home home; + private Picture picture; + private Calendar calendar; + private Person person; + + private int selectMenu; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_menu); + + selectMenu = 0; + bottomNavigationView = findViewById(R.id.bottomNavi); + + requestMicrophonePermission(); + if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { + // 권한이 없으면 요청 + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1); + } + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch(item.getItemId()){ + case R.id.action_home: + selectMenu = 0; + setFrag(0); + break; + case R.id.action_picture: + selectMenu = 1; + setFrag(1); + break; + case R.id.action_calendar: + selectMenu = 2; + setFrag(2); + break; + case R.id.action_notifications: + selectMenu = 3; + setFrag(3); + break; + } + return true; + } + }); + home = new Home(); + picture = new Picture(); + calendar = new Calendar(); + person = new Person(); + + setFrag(0); // 첫 프래그먼트 화면 + int selectedFragmentIndex = getIntent().getIntExtra("SELECTED_FRAGMENT_INDEX", 0); + setFrag(selectedFragmentIndex); + } + + // 프래그먼트 교체가 일어나는 실행문 + private void setFrag(int n){ + // 먼저 리스너를 제거 + bottomNavigationView.setOnNavigationItemSelectedListener(null); + + fm = getSupportFragmentManager(); + ft = fm.beginTransaction(); + switch (n){ + case 0: + ft.replace(R.id.main_frame, home); + ft.commit(); + bottomNavigationView.setSelectedItemId(R.id.action_home); + break; + case 1: + ft.replace(R.id.main_frame, picture); + ft.commit(); + bottomNavigationView.setSelectedItemId(R.id.action_picture); + break; + case 2: + ft.replace(R.id.main_frame, calendar); + ft.commit(); + bottomNavigationView.setSelectedItemId(R.id.action_calendar); + break; + case 3: + ft.replace(R.id.main_frame, person); + ft.commit(); + bottomNavigationView.setSelectedItemId(R.id.action_notifications); + break; + } + + // 다시 리스너를 설정 + bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch(item.getItemId()){ + case R.id.action_home: + selectMenu = 0; + setFrag(0); + break; + case R.id.action_picture: + selectMenu = 1; + setFrag(1); + break; + case R.id.action_calendar: + selectMenu = 2; + setFrag(2); + break; + case R.id.action_notifications: + selectMenu = 3; + setFrag(3); + break; + } + return true; + } + }); + } + + private void requestMicrophonePermission() { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + // 권한이 허용되지 않은 경우 요청 + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSIONS_REQUEST_RECORD_AUDIO); + } else { + // 권한이 이미 허용된 경우 + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + switch (requestCode) { + case PERMISSIONS_REQUEST_RECORD_AUDIO: + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + } else { + } + break; + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("홈") || str.equals("홈 화면")){ + setFrag(0); + }else if(str.equals("사진") || str.equals("카메라")){ + setFrag(1); + }else if(str.equals("스케줄러") || str.equals("달력")){ + setFrag(2); + }else if(str.equals("정보") || str.equals("내 정보")){ + setFrag(3); + } + if(selectMenu == 0){ + if(str.equals("자세교정") || str.equals("자세 교정")){ + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + }else if(str.equals("홈트레이닝") || str.equals("홈 트레이닝")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + finish(); + }else if(str.equals("기록측정") || str.equals("기록 측정")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + }else if(str.equals("랭킹") || str.equals("순위")){ + Intent intent = new Intent(getApplicationContext(), Ranking.class); + startActivity(intent); + finish(); + } + }else if(selectMenu == 1){ + if(str.equals("사진 촬영") || str.equals("사진촬영")) { + ((Picture) picture).takePicture(); // Picture 프래그먼트의 takePicture 메서드 호출 + } + }else if(selectMenu == 3){ + if(str.equals("수정") || str.equals("정보 수정")){ + Intent intent = new Intent(getApplicationContext(), MemberChangeActivity.class); + startActivity(intent); + } + } + } + restartVoiceRecognitionService(); + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} diff --git a/app/src/main/java/com/example/newbody/Notice.java b/app/src/main/java/com/example/newbody/Notice.java new file mode 100644 index 0000000..f8c1fb4 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Notice.java @@ -0,0 +1,14 @@ +package com.example.newbody; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; + +public class Notice extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_notice); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/OnDateSetListener.java b/app/src/main/java/com/example/newbody/OnDateSetListener.java new file mode 100644 index 0000000..a5aab0d --- /dev/null +++ b/app/src/main/java/com/example/newbody/OnDateSetListener.java @@ -0,0 +1,6 @@ +package com.example.newbody; + +public interface OnDateSetListener { + void onDateSet(int year, int month); +} + diff --git a/app/src/main/java/com/example/newbody/PayActivity.java b/app/src/main/java/com/example/newbody/PayActivity.java new file mode 100644 index 0000000..6be6889 --- /dev/null +++ b/app/src/main/java/com/example/newbody/PayActivity.java @@ -0,0 +1,217 @@ +package com.example.newbody; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.Spinner; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import kr.co.bootpay.android.Bootpay; +import kr.co.bootpay.android.events.BootpayEventListener; +import kr.co.bootpay.android.models.BootExtra; +import kr.co.bootpay.android.models.BootUser; +import kr.co.bootpay.android.models.Payload; + +public class PayActivity extends AppCompatActivity { + + private String application_id = "64f1c55dd25985001bda77d7"; + + private Button prev; + private ImageView pay_button; + + private String productName = "프리미엄"; // 상품 이름 + private String productPrice = "4900"; // 상품 가격 + + FirebaseUser user; + DatabaseReference databaseReference; + FirebaseAuth auth; + private FirebaseFirestore db; + + Spinner spinner_pg; + Spinner spinner_method; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pay); + + initViews(); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + + pay_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + goRequest(); + } + }); + } + + public void goRequest() { + + BootUser user = new BootUser().setPhone("010-9175-3460"); // 구매자 정보 + BootExtra extra = new BootExtra() + .setCardQuota("0,2,3"); // 일시불, 2개월, 3개월 할부 허용, 할부는 최대 12개월까지 사용됨 (5만원 이상 구매시 할부허용 범위) + + Double price = 100d; + + String pg = "이니시스"; + String method = "카드"; + + Payload payload = new Payload(); + payload.setApplicationId(application_id) + .setOrderName("프리미엄 멤버십 결제") + .setPg(pg) + .setOrderId("1234") + .setMethod(method) + .setPrice(price) + .setUser(user) + .setExtra(extra); + + Map map = new HashMap<>(); + map.put("1", "abcdef"); + map.put("2", "abcdef55"); + map.put("3", 1234); + payload.setMetadata(map); + + Bootpay.init(getSupportFragmentManager(), getApplicationContext()) + .setPayload(payload) + .setEventListener(new BootpayEventListener() { + @Override + public void onCancel(String data) { + Log.d("cancel", data); + } + + @Override + public void onError(String data) { + Log.d("error", data); + } + + @Override + public void onClose() { + Bootpay.removePaymentWindow(); + } + + @Override + public void onIssued(String data) { + Log.d("issued", data); + } + + @Override + public boolean onConfirm(String data) { + Log.d("confirm", data); +// Bootpay.transactionConfirm(data); //재고가 있어서 결제를 진행하려 할때 true (방법 1) + return true; //재고가 있어서 결제를 진행하려 할때 true (방법 2) +// return false; //결제를 진행하지 않을때 false + } + + @Override + public void onDone(String data) { + Log.d("done", data); + savePremium(); + saveOrUpdatePaymentData(productPrice); + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + + }).requestPayment(); + } + + private void savePremium(){ + Map userData = new HashMap<>(); + final String collectionName = "users"; + userData.put("grade", "프리미엄"); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveOrUpdatePaymentData(String paymentAmount) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.getDefault()); + String currentDate = sdf.format(new Date()); + final String collectionName = "payments"; + + DocumentReference paymentRecordRef = db.collection(collectionName).document(currentDate); + paymentRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 문서가 이미 존재하면, 금액을 업데이트 + long existingAmount = document.getLong("amount"); + long newAmount = existingAmount + Long.parseLong(paymentAmount); + paymentRecordRef.update("amount", newAmount); + } else { + // 문서가 존재하지 않으면, 새로운 문서 생성 + Map paymentData = new HashMap<>(); + paymentData.put("amount", Long.parseLong(paymentAmount)); + paymentRecordRef.set(paymentData); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + public void initViews(){ + prev = findViewById(R.id.prevButtonPay); + pay_button = findViewById(R.id.payButton); + auth = FirebaseAuth.getInstance(); + user = auth.getCurrentUser(); + db = FirebaseFirestore.getInstance(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Person.java b/app/src/main/java/com/example/newbody/Person.java new file mode 100644 index 0000000..d4870ae --- /dev/null +++ b/app/src/main/java/com/example/newbody/Person.java @@ -0,0 +1,248 @@ +package com.example.newbody; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.bumptech.glide.Glide; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Person extends Fragment { + private View view; + + FirebaseAuth auth; + Button button, infoButton, goalButton, progressButton, friendListButton, friendButton, payButton, inviteButton; + FirebaseUser user; + + FirebaseFirestore db; + TextView name, height, weight, age; + + SimpleDateFormat yy, md; + Date date; + View fixButton, premiumCheckLayout; + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + view = inflater.inflate(R.layout.activity_person, container, false); + + db = FirebaseFirestore.getInstance(); + auth = FirebaseAuth.getInstance(); + button = view.findViewById(R.id.logout); + name = view.findViewById(R.id.user_name); + height = view.findViewById(R.id.height_data); + weight = view.findViewById(R.id.weight_data); + age = view.findViewById(R.id.age_data); + infoButton = view.findViewById(R.id.info_button); + goalButton = view.findViewById(R.id.goal_button); + progressButton = view.findViewById(R.id.progress_button); + friendListButton = view.findViewById(R.id.friend_list_button); + friendButton = view.findViewById(R.id.friend_button); + inviteButton = view.findViewById(R.id.friend_invite_button); + payButton = view.findViewById(R.id.pay_button); + premiumCheckLayout = view.findViewById(R.id.premium_check_layout); + + user = auth.getCurrentUser(); + date = new Date(); + yy = new SimpleDateFormat("yyyy"); + md = new SimpleDateFormat("MMdd"); + + fixButton = view.findViewById(R.id.fix); + + premiumCheck(); + + fixButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), MemberChangeActivity.class); + startActivity(intent); + } + }); + + db.collection("users").document(user.getUid()) + .get() + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(DocumentSnapshot documentSnapshot) { + if (documentSnapshot.exists()) { + String imageUrl = documentSnapshot.getString("imageUrl"); + if (!TextUtils.isEmpty(imageUrl)) { + loadImageIntoImageView(imageUrl); + } else { + } + } else { + + } + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + + if(user == null){ + Intent intent = new Intent(getActivity(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @SuppressLint("SetTextI18n") + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + int yearNum = Integer.parseInt(yy.format(date)); + int mdNum = Integer.parseInt(md.format(date)); + String birth = document.getString("birth"); + int year = Integer.parseInt(birth.substring(0, 4)); + int md = Integer.parseInt(birth.substring(4, 8)); + + if(md < mdNum){ + age.setText(Integer.toString(yearNum-year)); + }else{ + age.setText(Integer.toString(yearNum-year-1)); + } + + name.setText(document.getString("name")); + weight.setText(document.getString("weight")); + height.setText(document.getString("height")); + } else { + age.setText("0"); + name.setText("0"); + weight.setText("0"); + height.setText("0"); + } + } else { + // handle the failure case + } + } + }); + } + + infoButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), MemberInfo.class); + startActivity(intent); + } + }); + + goalButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), Target.class); + startActivity(intent); + } + }); + progressButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), Graph.class); + startActivity(intent); + } + }); + + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + FirebaseAuth.getInstance().signOut(); + Intent intent = new Intent(getActivity(), LoginActivity.class); + startActivity(intent); + } + }); + + friendListButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), FriendListPlus.class); + startActivity(intent); + } + }); + + friendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), FriendList.class); + startActivity(intent); + } + }); + + inviteButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), FriendInvite.class); + startActivity(intent); + } + }); + + payButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), PayActivity.class); + startActivity(intent); + } + }); + + return view; + } + + private void loadImageIntoImageView(String imageUrl) { + ImageView userImageView = view.findViewById(R.id.profile_pic); // Replace with your ImageView's ID + + Glide.with(this) + .load(imageUrl) + .circleCrop() + .into(userImageView); + } + + public void premiumCheck(){ + if(user == null){ + Intent intent = new Intent(getActivity(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String grade = document.getString("grade"); + if (grade == null) grade = "일반"; + + if(grade.equals("프리미엄")){ + premiumCheckLayout.setVisibility(View.GONE); + } + } + } else { + } + } + }); + } + } +} diff --git a/app/src/main/java/com/example/newbody/Picture.java b/app/src/main/java/com/example/newbody/Picture.java new file mode 100644 index 0000000..50a0a7a --- /dev/null +++ b/app/src/main/java/com/example/newbody/Picture.java @@ -0,0 +1,127 @@ +package com.example.newbody; + +import android.app.Activity; +import android.Manifest; +import android.content.ContentValues; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + +import java.io.OutputStream; +import java.util.ArrayList; + +public class Picture extends Fragment { + private static final int PERMISSIONS_REQUEST_CAMERA = 2; + static final int REQUEST_IMAGE_CAPTURE = 1; + private View view; + private View camera_button; + private Bitmap currentImageBitmap; + private Button save; + private Uri imageUri; + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_picture, container, false); + + camera_button = view.findViewById(R.id.camera_button); + save = view.findViewById(R.id.saveButton); + + camera_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + requestCameraPermission(); + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) { + startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); + } + } + }); + + save.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (currentImageBitmap != null) { + saveToGallery(currentImageBitmap); + } + Toast.makeText(getActivity(), "사진이 저장되었습니다", Toast.LENGTH_SHORT).show(); + } + }); + + return view; + } + + public void takePicture() { + requestCameraPermission(); + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) { + startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); + } + } + + + private void requestCameraPermission() { + if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(getActivity(), + new String[]{Manifest.permission.CAMERA}, + PERMISSIONS_REQUEST_CAMERA); + } + } + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == PERMISSIONS_REQUEST_CAMERA) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // 카메라 권한이 승인됐을 때 실행할 코드를 여기에 작성합니다. + } else { + // 사용자가 권한 요청을 거부했을 때 실행할 코드를 여기에 작성합니다. + } + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) { + save.setVisibility(View.VISIBLE); + Bundle extras = data.getExtras(); + currentImageBitmap = (Bitmap) extras.get("data"); + + ImageView imageView = (ImageView) getView().findViewById(R.id.pic_image); + imageView.setImageBitmap(currentImageBitmap); + } + } + + private void saveToGallery(Bitmap bitmap) { + ContentValues values = new ContentValues(); + values.put(MediaStore.Images.Media.TITLE, "New Picture"); + values.put(MediaStore.Images.Media.DESCRIPTION, "From Camera"); + values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); + + Uri uri = getActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); + + try { + OutputStream outputStream = getActivity().getContentResolver().openOutputStream(uri); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); + outputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/example/newbody/PoseMatcher.java b/app/src/main/java/com/example/newbody/PoseMatcher.java new file mode 100644 index 0000000..4926fb8 --- /dev/null +++ b/app/src/main/java/com/example/newbody/PoseMatcher.java @@ -0,0 +1,77 @@ +package com.example.newbody; + +import static java.lang.Math.abs; +import static java.lang.Math.atan2; +import static java.lang.Math.toDegrees; + +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseLandmark; + +public class PoseMatcher { + + private static final double OFFSET = 15.0; + + public boolean match(Pose pose, TargetPose targetPose) { + return extractAndMatch(pose, targetPose); + } + + public boolean extractAndMatch(Pose pose, TargetPose targetPose) { + for (TargetShape target : targetPose.getTargets()) { + LandmarkTriple triple = extractLandmark(pose, target); + PoseLandmark firstLandmark = triple.getFirstLandmark(); + PoseLandmark middleLandmark = triple.getMiddleLandmark(); + PoseLandmark lastLandmark = triple.getLastLandmark(); + + if (landmarkNotFound(firstLandmark, middleLandmark, lastLandmark)) { + return false; + } + + double angle = calculateAngle(firstLandmark, middleLandmark, lastLandmark); + double targetAngle = target.getAngle(); + + if (abs(angle - targetAngle) > OFFSET) { + return false; + } + } + return true; + } + + public LandmarkTriple extractLandmark(Pose pose, TargetShape target) { + return new LandmarkTriple( + extractLandmarkFromType(pose, target.getFirstLandmarkType()), + extractLandmarkFromType(pose, target.getMiddleLandmarkType()), + extractLandmarkFromType(pose, target.getLastLandmarkType()) + ); + } + + public PoseLandmark extractLandmarkFromType(Pose pose, int landmarkType) { + return pose.getPoseLandmark(landmarkType); + } + + public boolean landmarkNotFound(PoseLandmark firstLandmark, PoseLandmark middleLandmark, PoseLandmark lastLandmark) { + return firstLandmark == null || middleLandmark == null || lastLandmark == null; + } + + public double calculateAngle(PoseLandmark firstLandmark, PoseLandmark middleLandmark, PoseLandmark lastLandmark) { + double angle = toDegrees( + atan2( + lastLandmark.getPosition().y - middleLandmark.getPosition().y, + lastLandmark.getPosition().x - middleLandmark.getPosition().x + ) - atan2( + firstLandmark.getPosition().y - middleLandmark.getPosition().y, + firstLandmark.getPosition().x - middleLandmark.getPosition().x + ) + ); + + double absoluteAngle = abs(angle); + if (absoluteAngle > 180) { + absoluteAngle = 360 - absoluteAngle; + } + return absoluteAngle; + } + + public boolean anglesMatch(double angle, double targetAngle) { + return angle < targetAngle + OFFSET && angle > targetAngle - OFFSET; + } +} + diff --git a/app/src/main/java/com/example/newbody/Posture.java b/app/src/main/java/com/example/newbody/Posture.java new file mode 100644 index 0000000..647544b --- /dev/null +++ b/app/src/main/java/com/example/newbody/Posture.java @@ -0,0 +1,401 @@ +package com.example.newbody; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.posture.PostureInfo; +import com.example.newbody.record.RecordDumbbell; +import com.example.newbody.record.RecordLegRaise; +import com.example.newbody.record.RecordPushup; +import com.example.newbody.record.RecordSidelateralraise; +import com.example.newbody.record.RecordSquat; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; + + +public class Posture extends AppCompatActivity { + private View ex_start; + private View []ex = new View[8]; + private TextView []exName = new TextView[8]; + private TextView []premiumMessage = new TextView[3]; + private View []lockButton = new View[3]; + private TextView selectE, pre1, pre2; + private Button prev; + private Switch customized; + private View squatView, pushupView, dumbbellView, sideView, legView, dumbbellCurlView, dumbbellFlyView, dumbbellTricepsView; + private FirebaseAuth mAuth; + private FirebaseFirestore db; + private FirebaseUser user; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.acticity_posture); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + initViews(); + premiumCheck(); + + customized.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + if(customized.isChecked()){ + pre1.setText(" "); + pre2.setText(" "); + DocumentReference userRecordRef = db.collection("users").document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String preference1 = document.getString("preference1"); + pre1.setText(preference1); + String preference2 = document.getString("preference2"); + pre2.setText(preference2); + + if(preference1.equals("도구 이용 운동")){ + squatView.setVisibility(View.GONE); + pushupView.setVisibility(View.GONE); + legView.setVisibility(View.GONE); + }else if(preference1.equals("맨몸 운동")){ + dumbbellCurlView.setVisibility(View.GONE); + dumbbellFlyView.setVisibility(View.GONE); + dumbbellTricepsView.setVisibility(View.GONE); + if(preference2.equals("팔 운동")){ + squatView.setVisibility(View.GONE); + dumbbellView.setVisibility(View.GONE); + sideView.setVisibility(View.GONE); + legView.setVisibility(View.GONE); + }else if(preference2.equals("하체 운동")){ + pushupView.setVisibility(View.GONE); + dumbbellView.setVisibility(View.GONE); + sideView.setVisibility(View.GONE); + }else if(preference2.equals("복근 운동")){ + squatView.setVisibility(View.GONE); + dumbbellView.setVisibility(View.GONE); + sideView.setVisibility(View.GONE); + } + } + } else { + Log.d("Firestore", "No such document"); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + }else if(!customized.isChecked()){ + squatView.setVisibility(View.VISIBLE); + pushupView.setVisibility(View.VISIBLE); + dumbbellView.setVisibility(View.VISIBLE); + sideView.setVisibility(View.VISIBLE); + legView.setVisibility(View.VISIBLE); + dumbbellCurlView.setVisibility(View.VISIBLE); + dumbbellFlyView.setVisibility(View.VISIBLE); + dumbbellTricepsView.setVisibility(View.VISIBLE); + } + } + }); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + }); + ex[0].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[0].getText()); + } + }); + ex[1].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[1].getText()); + } + }); + ex[2].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[2].getText()); + } + }); + + ex[3].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[3].getText()); + } + }); + + ex[4].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[4].getText()); + } + }); + + ex[5].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[5].getText()); + } + }); + + ex[6].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[6].getText()); + } + }); + + ex[7].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[7].getText()); + } + }); + + lockButton[0].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(Posture.this, "프리미엄 전용 운동입니다", Toast.LENGTH_SHORT).show(); + } + }); + + lockButton[1].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(Posture.this, "프리미엄 전용 운동입니다", Toast.LENGTH_SHORT).show(); + } + }); + + lockButton[2].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(Posture.this, "프리미엄 전용 운동입니다", Toast.LENGTH_SHORT).show(); + } + }); + + ex_start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(selectE.getText().equals("운동")){ + Toast.makeText(Posture.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + Intent intent = new Intent(getApplicationContext(), PostureInfo.class); + intent.putExtra("exercise", selectE.getText()); + startActivity(intent); + finish(); + } + }); + + } + private void initViews(){ + ex_start = findViewById(R.id.start_button); + ex[0] = findViewById(R.id.ex_button1); + ex[1] = findViewById(R.id.ex_button2); + ex[2] = findViewById(R.id.ex_button3); + ex[3] = findViewById(R.id.ex_button4); + ex[4] = findViewById(R.id.ex_button5); + ex[5] = findViewById(R.id.ex_button6); + ex[6] = findViewById(R.id.ex_button7); + ex[7] = findViewById(R.id.ex_button8); + exName[0] = findViewById(R.id.ex1_name); + exName[1] = findViewById(R.id.ex2_name); + exName[2] = findViewById(R.id.ex3_name); + exName[3] = findViewById(R.id.ex4_name); + exName[4] = findViewById(R.id.ex5_name); + exName[5] = findViewById(R.id.ex6_name); + exName[6] = findViewById(R.id.ex7_name); + exName[7] = findViewById(R.id.ex8_name); + selectE = findViewById(R.id.exercise_select); + prev = findViewById(R.id.prevButton); + squatView = findViewById(R.id.squatView1); + pushupView = findViewById(R.id.pushupView1); + dumbbellView = findViewById(R.id.dumbbellView1); + sideView = findViewById(R.id.sideView1); + legView = findViewById(R.id.legView1); + dumbbellCurlView = findViewById(R.id.dumbbellCurlView); + dumbbellFlyView = findViewById(R.id.dumbbellFlyView); + dumbbellTricepsView = findViewById(R.id.dumbbellTricepsView); + customized = findViewById(R.id.customized2); + mAuth = FirebaseAuth.getInstance(); + db = FirebaseFirestore.getInstance(); + user = mAuth.getCurrentUser(); + pre1 = findViewById(R.id.pre11); + pre2 = findViewById(R.id.pre22); + premiumMessage[0] = findViewById(R.id.premiumMessage6); + premiumMessage[1] = findViewById(R.id.premiumMessage7); + premiumMessage[2] = findViewById(R.id.premiumMessage8); + lockButton[0] = findViewById(R.id.ex_lock_button6); + lockButton[1] = findViewById(R.id.ex_lock_button7); + lockButton[2] = findViewById(R.id.ex_lock_button8); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("스쿼트") || str.equals("푸쉬업") || str.equals("푸시업") || str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스") || + str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈") || str.equals("레그 레이즈") || str.equals("레그레이즈") || + str.equals("덤벨컬") || str.equals("덤벨 컬") || str.equals("덤벨 플라이") || str.equals("덤벨플라이") || str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + if(str.equals("스쿼트")){ + selectE.setText(exName[0].getText()); + }else if(str.equals("푸쉬업") || str.equals("푸시업")){ + selectE.setText(exName[1].getText()); + }else if(str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스")){ + selectE.setText(exName[2].getText()); + }else if(str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈")){ + selectE.setText(exName[3].getText()); + }else if(str.equals("레그 레이즈") || str.equals("레그레이즈")){ + selectE.setText(exName[4].getText()); + }else if(str.equals("덤벨컬") || str.equals("덤벨 컬")){ + selectE.setText(exName[5].getText()); + }else if(str.equals("덤벨 플라이") || str.equals("덤벨플라이")){ + selectE.setText(exName[6].getText()); + }else if(str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + selectE.setText(exName[7].getText()); + } + }else if(str.equals("시작") || str.equals("운동 시작")){ + if(selectE.getText().equals("운동")){ + Toast.makeText(Posture.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + Intent intent = new Intent(getApplicationContext(), PostureInfo.class); + intent.putExtra("exercise", selectE.getText()); + startActivity(intent); + finish(); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + public void premiumCheck(){ + if(user == null){ + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String grade = document.getString("grade"); + if (grade == null) grade = "일반"; + + if(grade.equals("프리미엄")){ + customized.setVisibility(View.VISIBLE); + premiumMessage[0].setVisibility(View.GONE); + premiumMessage[1].setVisibility(View.GONE); + premiumMessage[2].setVisibility(View.GONE); + lockButton[0].setVisibility(View.GONE); + lockButton[1].setVisibility(View.GONE); + lockButton[2].setVisibility(View.GONE); + ex[5].setVisibility(View.VISIBLE); + ex[6].setVisibility(View.VISIBLE); + ex[7].setVisibility(View.VISIBLE); + } + } + } else { + } + } + }); + } + } +} diff --git a/app/src/main/java/com/example/newbody/PushMessage/AndroidNewFCM.java b/app/src/main/java/com/example/newbody/PushMessage/AndroidNewFCM.java new file mode 100644 index 0000000..9b60b2c --- /dev/null +++ b/app/src/main/java/com/example/newbody/PushMessage/AndroidNewFCM.java @@ -0,0 +1,143 @@ +package com.example.newbody.PushMessage; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.widget.Button; +import android.widget.Toast; +import com.example.newbody.Membership3; +import com.example.newbody.R; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.messaging.FirebaseMessaging; + +import org.json.JSONObject; + +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import butterknife.BindView; +import butterknife.ButterKnife; + +public class AndroidNewFCM extends AppCompatActivity { + + @BindView(R.id.btn_get_token) + Button btn_get_token; + + private static final String TAG = "AndroidNewFCM"; + private FirebaseFirestore db; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_android_new_fcm); + ButterKnife.bind(this); + + db = FirebaseFirestore.getInstance(); + + btn_get_token.setOnClickListener((view) -> { + FirebaseMessaging.getInstance().getToken() + .addOnSuccessListener(token -> { + Log.d(TAG, token); + + // 토큰을 Firestore에 저장하는 로직 + Map tokenData = new HashMap<>(); + tokenData.put("token", token); + + db.collection("pushMessage").add(tokenData) + .addOnSuccessListener(documentReference -> Log.d(TAG, "Token saved with ID: " + documentReference.getId())) + .addOnFailureListener(e -> Log.w(TAG, "Error adding token", e)); + + }) + .addOnFailureListener(e -> Toast.makeText(this, "Failed to get token", Toast.LENGTH_SHORT).show()); + }); + + } + + public void saveUserDataAndNotification(String userUID, Map userData, String name) { + db.collection("users").document(userUID) + .set(userData) + .addOnSuccessListener(aVoid -> { + FirebaseMessaging.getInstance().getToken() + .addOnCompleteListener(task -> { + if (!task.isSuccessful()) { + Log.w(TAG, "Fetching FCM registration token failed", task.getException()); + return; + } + String token = task.getResult(); + Map tokenData = new HashMap<>(); + tokenData.put("token", token); + + db.collection("pushMessage").add(tokenData) + .addOnSuccessListener(documentReference -> Log.d(TAG, "Token saved with ID: " + documentReference.getId())) + .addOnFailureListener(e -> Log.w(TAG, "Error adding token", e)); + }) + .addOnFailureListener(e -> { + Log.w(TAG, "Failed to get FCM token", e); + }); + + Map notificationData = new HashMap<>(); + notificationData.put("title", "환영합니다!"); + notificationData.put("body", name + "님 회원가입을 축하합니다."); + + db.collection("pushMessage").add(notificationData) + .addOnSuccessListener(documentReference -> { + Log.d("Firestore", "Notification saved with ID: " + documentReference.getId()); + PushNotificationService pushService = new PushNotificationService(); + pushService.sendNotificationToUser(userUID, "환영합니다!", name + "님 회원가입을 축하합니다."); + }) + .addOnFailureListener(e -> Log.w("Firestore", "Error adding notification", e)); + + Toast.makeText(AndroidNewFCM.this, "Data saved successfully.", Toast.LENGTH_SHORT).show(); + Intent intent = new Intent(getApplicationContext(), Membership3.class); + startActivity(intent); + finish(); + }) + .addOnFailureListener(e -> { + Log.w(TAG, "Failed to set user data in Firestore", e); + Toast.makeText(AndroidNewFCM.this, "Failed to save data.", Toast.LENGTH_SHORT).show(); + }); + } +} + +class PushNotificationService { + public void sendNotificationToUser(String userFCMToken, String title, String body) { + try { + String fcmUrl = "https://fcm.googleapis.com/fcm/send"; + JSONObject root = new JSONObject(); + JSONObject notification = new JSONObject(); + notification.put("title", title); + notification.put("body", body); + root.put("notification", notification); + root.put("to", userFCMToken); + + URL url = new URL(fcmUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + connection.setDoInput(true); + String serverKey = "BKKukGOqiZ3gPBnvKuH4WQ4g8uuKisF5vSYw4o6DRLjqlF3g6EGBZPCFKxgRYeMiUTgqlWgfjHMMx1-MRDzopIQ"; + connection.setRequestProperty("Authorization", "key=" + serverKey); + connection.setRequestProperty("Content-Type", "application/json"); + + OutputStream os = connection.getOutputStream(); + os.write(root.toString().getBytes("UTF-8")); + os.close(); + + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + Log.d("FCM", "Notification sent successfully"); + } else { + Log.e("FCM", "Failed to send notification. Response code: " + responseCode); + } + } catch (Exception e) { + Log.e("FCM", "Exception while sending notification", e); + } + } +} diff --git a/app/src/main/java/com/example/newbody/PushMessage/MyFirebaseService.java b/app/src/main/java/com/example/newbody/PushMessage/MyFirebaseService.java new file mode 100644 index 0000000..4c51a33 --- /dev/null +++ b/app/src/main/java/com/example/newbody/PushMessage/MyFirebaseService.java @@ -0,0 +1,31 @@ +package com.example.newbody.PushMessage; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.google.firebase.messaging.FirebaseMessagingService; +import com.google.firebase.messaging.RemoteMessage; +import com.google.gson.Gson; + +public class MyFirebaseService extends FirebaseMessagingService { + @Override + public void onNewToken(@NonNull String token) { + super.onNewToken(token); + //Submit to save with you need + Log.d(Utils.TAG,token); + } + + @Override + public void onMessageReceived(@NonNull RemoteMessage message) { + super.onMessageReceived(message); + //show notification when we receive it + String title = message.getNotification().getTitle(); + String content = message.getNotification().getBody(); + String data = new Gson().toJson(message.getData()); + + //Create notification to show + Utils.showNotification(this,title,content); + //Show raw data by log + Log.d(Utils.TAG,data); + } +} diff --git a/app/src/main/java/com/example/newbody/PushMessage/Utils.java b/app/src/main/java/com/example/newbody/PushMessage/Utils.java new file mode 100644 index 0000000..d720222 --- /dev/null +++ b/app/src/main/java/com/example/newbody/PushMessage/Utils.java @@ -0,0 +1,45 @@ +package com.example.newbody.PushMessage; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; + +import androidx.core.app.NotificationCompat; + +import com.example.newbody.R; + +import java.util.Random; + +public class Utils { + public static final String TAG = "EDMTDEV"; + + public static void showNotification(Context context,String title,String body) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(context,"edmt.dev.channel"); + + builder.setSmallIcon(R.drawable.ic_launcher_background); + builder.setContentTitle(title); + builder.setContentText(body); + builder.setPriority(NotificationCompat.PRIORITY_MAX); + + //style + NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); + bigTextStyle.bigText(title); + bigTextStyle.setBigContentTitle(title); + bigTextStyle.setSummaryText(title); + + builder.setStyle(bigTextStyle); + + NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ + String channelId = "edmt.dev.channel.id"; + NotificationChannel channel = new NotificationChannel(channelId, "EDMTDEV Channel", + NotificationManager.IMPORTANCE_HIGH); + manager.createNotificationChannel(channel); + builder.setChannelId(channelId); + } + + manager.notify(new Random().nextInt(),builder.build()); + } +} diff --git a/app/src/main/java/com/example/newbody/Ranking.java b/app/src/main/java/com/example/newbody/Ranking.java new file mode 100644 index 0000000..cfec0b3 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Ranking.java @@ -0,0 +1,494 @@ +package com.example.newbody; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class Ranking extends AppCompatActivity { + + private Button prev, range, exercise, time, ranking_button; + private String select_time, select_ex, select_range; + private ArrayList uidList; + private View rankingView; + + private RecyclerView rankingRecyclerView; + private RankingAdapter adapter; + private FirebaseFirestore db; + private FirebaseUser user; + private List rankingList = new ArrayList<>(); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_ranking); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + initViews(); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + }); + + range.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) {showRangeDialog();} + }); + exercise.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) {showExerciseDialog();} + }); + time.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) {showTimeDialog();} + }); + + ranking_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(range.getText().equals("범위")){ + Toast.makeText(Ranking.this, "범위를 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(exercise.getText().equals("운동")){ + Toast.makeText(Ranking.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(time.getText().equals("시간")){ + Toast.makeText(Ranking.this, "시간을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + + rankingView.setVisibility(View.VISIBLE); + db = FirebaseFirestore.getInstance(); + rankingRecyclerView.setLayoutManager(new LinearLayoutManager(Ranking.this)); + + fetchData(); + adapter = new RankingAdapter(rankingList); + rankingRecyclerView.setAdapter(adapter); + } + }); + } + public void initViews(){ + prev = findViewById(R.id.prevButtonRanking); + range = findViewById(R.id.range); + exercise = findViewById(R.id.exercise); + time = findViewById(R.id.timeRanking); + ranking_button = findViewById(R.id.ranking_info_button); + rankingRecyclerView = findViewById(R.id.rankingRecyclerView); + rankingView = findViewById(R.id.layout_ranking); + uidList = new ArrayList<>(); + } + + private void showTimeDialog() { + final String[] difficultyOptions = {"1분", "2분", "3분"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("시간 선택"); + builder.setItems(difficultyOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_time = difficultyOptions[which]; + time.setText(select_time); + } + }); + builder.show(); + } + + private void showExerciseDialog() { + final String[] exOptions = {"스쿼트", "푸쉬업", "덤벨 숄더 프레스", "사이드 레터럴 레이즈", "레그 레이즈", "덤벨 컬", "덤벨 플라이", "덤벨 트라이셉스 익스텐션"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("운동 선택"); + builder.setItems(exOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_ex = exOptions[which]; + exercise.setText(select_ex); + } + }); + builder.show(); + } + private void showRangeDialog() { + final String[] rangeOptions = {"전체", "친구"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("범위 선택"); + builder.setItems(rangeOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_range = rangeOptions[which]; + range.setText(select_range); + } + }); + builder.show(); + } + + private void fetchData() { + AtomicInteger rank_in = new AtomicInteger(1); + rankingList.clear(); + String collectionName = null; + if(range.getText().equals("전체")){ + if(exercise.getText().equals("스쿼트")){ + if(time.getText().equals("1분")){ + collectionName = "countSquat1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countSquat2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countSquat3Minute"; + } + }else if(exercise.getText().equals("푸쉬업")){ + if(time.getText().equals("1분")){ + collectionName = "countPushup1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countPushup2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countPushup3Minute"; + } + }else if(exercise.getText().equals("덤벨 숄더 프레스")){ + if(time.getText().equals("1분")){ + collectionName = "countDumbbell1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countDumbbell2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countDumbbell3Minute"; + } + }else if(exercise.getText().equals("사이드 레터럴 레이즈")){ + if(time.getText().equals("1분")){ + collectionName = "countSide1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countSide2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countSide3Minute"; + } + }else if(exercise.getText().equals("레그 레이즈")){ + if(time.getText().equals("1분")){ + collectionName = "countLeg1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countLeg2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countLeg3Minute"; + } + }else if(exercise.getText().equals("덤벨 컬")){ + if(time.getText().equals("1분")){ + collectionName = "countCurl1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countCurl2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countCurl3Minute"; + } + }else if(exercise.getText().equals("덤벨 플라이")){ + if(time.getText().equals("1분")){ + collectionName = "countFly1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countFly2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countFly3Minute"; + } + }else if(exercise.getText().equals("덤벨 트라이셉스 익스텐션")){ + if(time.getText().equals("1분")){ + collectionName = "countTriceps1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countTriceps2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countTriceps3Minute"; + } + } + String finalCollectionName = collectionName; + db.collection(collectionName).orderBy(collectionName, Query.Direction.DESCENDING) + .get() + .addOnCompleteListener(task -> { + if (task.isSuccessful()) { + for (QueryDocumentSnapshot document : task.getResult()) { + String name = document.getString("name"); + int score = document.getLong(finalCollectionName).intValue(); + + rankingList.add(new RankingItem(rank_in.get(), name, score)); + rank_in.getAndIncrement(); + } + adapter.notifyDataSetChanged(); + } + }); + }else if(range.getText().equals("친구")){ + if(exercise.getText().equals("스쿼트")){ + if(time.getText().equals("1분")){ + collectionName = "countSquat1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countSquat2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countSquat3Minute"; + } + }else if(exercise.getText().equals("푸쉬업")){ + if(time.getText().equals("1분")){ + collectionName = "countPushup1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countPushup2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countPushup3Minute"; + } + }else if(exercise.getText().equals("덤벨 숄더 프레스")){ + if(time.getText().equals("1분")){ + collectionName = "countDumbbell1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countDumbbell2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countDumbbell3Minute"; + } + }else if(exercise.getText().equals("사이드 레터럴 레이즈")){ + if(time.getText().equals("1분")){ + collectionName = "countSide1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countSide2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countSide3Minute"; + } + }else if(exercise.getText().equals("레그 레이즈")){ + if(time.getText().equals("1분")){ + collectionName = "countLeg1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countLeg2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countLeg3Minute"; + } + }else if(exercise.getText().equals("덤벨 컬")){ + if(time.getText().equals("1분")){ + collectionName = "countCurl1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countCurl2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countCurl3Minute"; + } + }else if(exercise.getText().equals("덤벨 플라이")){ + if(time.getText().equals("1분")){ + collectionName = "countFly1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countFly2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countFly3Minute"; + } + }else if(exercise.getText().equals("덤벨 트라이셉스 익스텐션")){ + if(time.getText().equals("1분")){ + collectionName = "countTriceps1Minute"; + }else if(time.getText().equals("2분")){ + collectionName = "countTriceps2Minute"; + }else if(time.getText().equals("3분")){ + collectionName = "countTriceps3Minute"; + } + } + friendListInput(); + String finalCollectionName = collectionName; + db.collection(collectionName) + .orderBy(collectionName, Query.Direction.DESCENDING) + .get() + .addOnCompleteListener(task -> { + if (task.isSuccessful()) { + for (QueryDocumentSnapshot document : task.getResult()) { + String docId = document.getId(); // 문서의 ID (여기서는 친구의 UID) + + if (uidList.contains(docId)) { // 문서의 ID가 친구 UID 리스트에 있는 경우만 추가 + String name = document.getString("name"); + int score = document.getLong(finalCollectionName).intValue(); + + rankingList.add(new RankingItem(rank_in.get(), name, score)); + rank_in.getAndIncrement(); + } + } + adapter.notifyDataSetChanged(); + } + }); + + } + } + + public void friendListInput(){ + FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); + String currentUid = currentUser != null ? currentUser.getUid() : null; + FirebaseFirestore db = FirebaseFirestore.getInstance(); + uidList.clear(); + + if (currentUid != null) { + db.collection("users") + .document(currentUid) + .collection("friends") + .get() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + for (QueryDocumentSnapshot document : task.getResult()) { + String friendUid = document.getString("uid"); + uidList.add(friendUid); + } + uidList.add(currentUid); + for (String uid : uidList) { + Log.d("Friend UID", uid); + } + + } else { + Log.d("Firestore", "Error getting documents: ", task.getException()); + } + } + }); + } + + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("1분") || str.equals("2분") || str.equals("3분")){ + time.setText(str); + }else if(str.equals("전체") || str.equals("친구")){ + range.setText(str); + }else if(str.equals("스쿼트") || str.equals("푸쉬업") || str.equals("푸시업") || str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스") || + str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈") || str.equals("레그 레이즈") || str.equals("레그레이즈") || + str.equals("덤벨컬") || str.equals("덤벨 컬") || str.equals("덤벨 플라이") || str.equals("덤벨플라이") || str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + if(str.equals("스쿼트")){ + exercise.setText("스쿼트"); + }else if(str.equals("푸쉬업") || str.equals("푸시업")){ + exercise.setText("푸쉬업"); + }else if(str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스")){ + exercise.setText("덤벨 숄더 프레스"); + }else if(str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈")){ + exercise.setText("사이드 레터럴 레이즈"); + }else if(str.equals("레그 레이즈") || str.equals("레그레이즈")){ + exercise.setText("레그 레이즈"); + }else if(str.equals("덤벨컬") || str.equals("덤벨 컬")){ + exercise.setText("덤벨 컬"); + }else if(str.equals("덤벨 플라이") || str.equals("덤벨플라이")){ + exercise.setText("덤벨 플라이"); + }else if(str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + exercise.setText("덤벨 트라이셉스 익스텐션"); + } + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + }else if(str.equals("순위조회") || str.equals("순위 조회") || str.equals("순위") || str.equals("랭킹 보여줘")){ + if(range.getText().equals("범위")){ + Toast.makeText(Ranking.this, "범위를 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(exercise.getText().equals("운동")){ + Toast.makeText(Ranking.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(time.getText().equals("시간")){ + Toast.makeText(Ranking.this, "시간을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + db = FirebaseFirestore.getInstance(); + rankingRecyclerView.setLayoutManager(new LinearLayoutManager(Ranking.this)); + + fetchData(); + adapter = new RankingAdapter(rankingList); + rankingRecyclerView.setAdapter(adapter); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + static class RankingItem { + int rank; + String name; + int score; + + public RankingItem(int rank, String name, int score) { + this.rank = rank; + this.name = name; + this.score = score; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/RankingAdapter.java b/app/src/main/java/com/example/newbody/RankingAdapter.java new file mode 100644 index 0000000..90a373d --- /dev/null +++ b/app/src/main/java/com/example/newbody/RankingAdapter.java @@ -0,0 +1,52 @@ +package com.example.newbody; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import java.util.List; + +public class RankingAdapter extends RecyclerView.Adapter { + + private List rankingList; + + public RankingAdapter(List rankingList) { + this.rankingList = rankingList; + } + + @NonNull + @Override + public RankingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.ranking_item, parent, false); + return new RankingViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull RankingViewHolder holder, int position) { + Ranking.RankingItem currentItem = rankingList.get(position); + holder.rankTextView.setText(String.valueOf(currentItem.rank)); + holder.nameTextView.setText(currentItem.name); + holder.scoreTextView.setText(String.valueOf(currentItem.score)); + } + + @Override + public int getItemCount() { + return rankingList.size(); + } + + static class RankingViewHolder extends RecyclerView.ViewHolder { + TextView rankTextView; + TextView nameTextView; + TextView scoreTextView; + + public RankingViewHolder(@NonNull View itemView) { + super(itemView); + rankTextView = itemView.findViewById(R.id.rankTextView); + nameTextView = itemView.findViewById(R.id.nameTextView); + scoreTextView = itemView.findViewById(R.id.scoreTextView); + } + } +} diff --git a/app/src/main/java/com/example/newbody/Record.java b/app/src/main/java/com/example/newbody/Record.java new file mode 100644 index 0000000..6780330 --- /dev/null +++ b/app/src/main/java/com/example/newbody/Record.java @@ -0,0 +1,641 @@ +package com.example.newbody; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.record.RecordCurl; +import com.example.newbody.record.RecordDumbbell; +import com.example.newbody.record.RecordFly; +import com.example.newbody.record.RecordLegRaise; +import com.example.newbody.record.RecordPushup; +import com.example.newbody.record.RecordSidelateralraise; +import com.example.newbody.record.RecordSquat; +import com.example.newbody.record.RecordTriceps; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; + +public class Record extends AppCompatActivity { + + private String select_time, select_ex; + private long[] totalTimesInMillis = {1 * 60 * 1000, 2 * 60 * 1000, 3 * 60 * 1000}; + private Button time; + private View ex_start; + private View squatView, pushupView, dumbbellView, sideView, legView, dumbbellCurlView, dumbbellFlyView, dumbbellTricepsView; + private View []ex = new View[8]; + private TextView []exName = new TextView[8]; + private TextView []premiumMessage = new TextView[3]; + private View []lockButton = new View[3]; + private TextView selectT, selectE, pre1, pre2; + private int select_num; + private Button prev; + private Switch customized; + + private FirebaseAuth mAuth; + private FirebaseFirestore db; + private FirebaseUser user; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + initViews(); + premiumCheck(); + customized.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + if(customized.isChecked()){ + pre1.setText(" "); + pre2.setText(" "); + DocumentReference userRecordRef = db.collection("users").document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String preference1 = document.getString("preference1"); + pre1.setText(preference1); + String preference2 = document.getString("preference2"); + pre2.setText(preference2); + + if(preference1.equals("도구 이용 운동")){ + squatView.setVisibility(View.GONE); + pushupView.setVisibility(View.GONE); + legView.setVisibility(View.GONE); + }else if(preference1.equals("맨몸 운동")){ + dumbbellCurlView.setVisibility(View.GONE); + dumbbellFlyView.setVisibility(View.GONE); + dumbbellTricepsView.setVisibility(View.GONE); + if(preference2.equals("팔 운동")){ + squatView.setVisibility(View.GONE); + dumbbellView.setVisibility(View.GONE); + sideView.setVisibility(View.GONE); + legView.setVisibility(View.GONE); + }else if(preference2.equals("하체 운동")){ + pushupView.setVisibility(View.GONE); + dumbbellView.setVisibility(View.GONE); + sideView.setVisibility(View.GONE); + }else if(preference2.equals("복근 운동")){ + squatView.setVisibility(View.GONE); + dumbbellView.setVisibility(View.GONE); + sideView.setVisibility(View.GONE); + } + } + } else { + Log.d("Firestore", "No such document"); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + }else if(!customized.isChecked()){ + squatView.setVisibility(View.VISIBLE); + pushupView.setVisibility(View.VISIBLE); + dumbbellView.setVisibility(View.VISIBLE); + sideView.setVisibility(View.VISIBLE); + legView.setVisibility(View.VISIBLE); + dumbbellCurlView.setVisibility(View.VISIBLE); + dumbbellFlyView.setVisibility(View.VISIBLE); + dumbbellTricepsView.setVisibility(View.VISIBLE); + } + } + }); + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + }); + time.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showTimeDialog(); + } + }); + + ex[0].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[0].getText()); + select_num = 1; + } + }); + ex[1].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[1].getText()); + select_num = 2; + } + }); + ex[2].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[2].getText()); + select_num = 3; + } + }); + + ex[3].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[3].getText()); + select_num = 4; + } + }); + + ex[4].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[4].getText()); + select_num = 5; + } + }); + + ex[5].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[5].getText()); + select_num = 6; + } + }); + + ex[6].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[6].getText()); + select_num = 7; + } + }); + + ex[7].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(exName[7].getText()); + select_num = 8; + } + }); + + lockButton[0].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(Record.this, "프리미엄 전용 운동입니다", Toast.LENGTH_SHORT).show(); + } + }); + + lockButton[1].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(Record.this, "프리미엄 전용 운동입니다", Toast.LENGTH_SHORT).show(); + } + }); + + lockButton[2].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(Record.this, "프리미엄 전용 운동입니다", Toast.LENGTH_SHORT).show(); + } + }); + + ex_start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(selectT.getText().equals("시간") || selectE.getText().equals("운동")){ + Toast.makeText(Record.this, "시간 또는 운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(select_num == 1){ + Intent intent = new Intent(Record.this, RecordSquat.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 2){ + Intent intent = new Intent(Record.this, RecordPushup.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 3){ + Intent intent = new Intent(Record.this, RecordDumbbell.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 4){ + Intent intent = new Intent(Record.this, RecordSidelateralraise.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 5){ + Intent intent = new Intent(Record.this, RecordLegRaise.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 6){ + Intent intent = new Intent(Record.this, RecordCurl.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 7){ + Intent intent = new Intent(Record.this, RecordFly.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 8){ + Intent intent = new Intent(Record.this, RecordTriceps.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + } + } + }); + + } + + public void initViews(){ + time = findViewById(R.id.time); + ex_start = findViewById(R.id.start_button); + ex[0] = findViewById(R.id.ex_button1); + ex[1] = findViewById(R.id.ex_button2); + ex[2] = findViewById(R.id.ex_button3); + ex[3] = findViewById(R.id.ex_button4); + ex[4] = findViewById(R.id.ex_button5); + ex[5] = findViewById(R.id.ex_button6); + ex[6] = findViewById(R.id.ex_button7); + ex[7] = findViewById(R.id.ex_button8); + exName[0] = findViewById(R.id.ex1_name); + exName[1] = findViewById(R.id.ex2_name); + exName[2] = findViewById(R.id.ex3_name); + exName[3] = findViewById(R.id.ex4_name); + exName[4] = findViewById(R.id.ex5_name); + exName[5] = findViewById(R.id.ex6_name); + exName[6] = findViewById(R.id.ex7_name); + exName[7] = findViewById(R.id.ex8_name); + selectT = findViewById(R.id.time_select); + selectE = findViewById(R.id.exercise_select); + prev = findViewById(R.id.prevButtonRecord); + squatView = findViewById(R.id.squatView); + pushupView = findViewById(R.id.pushupView); + dumbbellView = findViewById(R.id.dumbbellView); + sideView = findViewById(R.id.sideView); + legView = findViewById(R.id.legView); + dumbbellCurlView = findViewById(R.id.dumbbellCurlView); + dumbbellFlyView = findViewById(R.id.dumbbellFlyView); + dumbbellTricepsView = findViewById(R.id.dumbbellTricepsView); + customized = findViewById(R.id.customized1); + mAuth = FirebaseAuth.getInstance(); + db = FirebaseFirestore.getInstance(); + user = mAuth.getCurrentUser(); + pre1 = findViewById(R.id.pre1); + pre2 = findViewById(R.id.pre2); + premiumMessage[0] = findViewById(R.id.premiumMessage6); + premiumMessage[1] = findViewById(R.id.premiumMessage7); + premiumMessage[2] = findViewById(R.id.premiumMessage8); + lockButton[0] = findViewById(R.id.ex_lock_button6); + lockButton[1] = findViewById(R.id.ex_lock_button7); + lockButton[2] = findViewById(R.id.ex_lock_button8); + } + + private void showTimeDialog() { + final String[] difficultyOptions = {"1분", "2분", "3분"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("시간 선택"); + builder.setItems(difficultyOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + select_time = difficultyOptions[which]; + time.setText(select_time); + + // 선택한 난이도에 따라 시간 배열을 업데이트 + if (select_time.equals("1분")) { + selectT.setText("1분"); + } else if (select_time.equals("2분")) { + selectT.setText("2분"); + } else if (select_time.equals("3분")) { + selectT.setText("3분"); + } + } + }); + builder.show(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("1분") || str.equals("2분") || str.equals("3분")){ + // 선택한 난이도에 따라 시간 배열을 업데이트 + if (str.equals("1분")) { + select_time = "1분"; + time.setText(select_time); + selectT.setText("1분"); + } else if (str.equals("2분")) { + select_time = "2분"; + time.setText(select_time); + selectT.setText("2분"); + } else if (str.equals("3분")) { + select_time = "3분"; + time.setText(select_time); + selectT.setText("3분"); + } + }else if(str.equals("스쿼트") || str.equals("푸쉬업") || str.equals("푸시업") || str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스") || + str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈") || str.equals("레그 레이즈") || str.equals("레그레이즈") || + str.equals("덤벨컬") || str.equals("덤벨 컬") || str.equals("덤벨 플라이") || str.equals("덤벨플라이") || str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + if(str.equals("스쿼트")){ + selectE.setText(exName[0].getText()); + select_num = 1; + }else if(str.equals("푸쉬업") || str.equals("푸시업")){ + selectE.setText(exName[1].getText()); + select_num = 2; + }else if(str.equals("덤벨 숄더 프레스") || str.equals("덤벨 숄더") || str.equals("덤벨숄더프레스")){ + selectE.setText(exName[2].getText()); + select_num = 3; + }else if(str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈")){ + selectE.setText(exName[3].getText()); + select_num = 4; + }else if(str.equals("레그 레이즈") || str.equals("레그레이즈")){ + selectE.setText(exName[4].getText()); + select_num = 5; + }else if(str.equals("덤벨컬") || str.equals("덤벨 컬")){ + selectE.setText(exName[5].getText()); + select_num = 6; + }else if(str.equals("덤벨 플라이") || str.equals("덤벨플라이")){ + selectE.setText(exName[6].getText()); + select_num = 7; + }else if(str.equals("덤벨 트라이셉스 익스텐션") || str.equals("덤벨 트라이")){ + selectE.setText(exName[7].getText()); + select_num = 8; + } + }else if(str.equals("시작") || str.equals("운동 시작")){ + if(selectT.getText().equals("시간") || selectE.getText().equals("운동")){ + Toast.makeText(Record.this, "시간 또는 운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + if(select_num == 1){ + Intent intent = new Intent(Record.this, RecordSquat.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 2){ + Intent intent = new Intent(Record.this, RecordPushup.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 3){ + Intent intent = new Intent(Record.this, RecordDumbbell.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 4){ + Intent intent = new Intent(Record.this, RecordSidelateralraise.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 5){ + Intent intent = new Intent(Record.this, RecordLegRaise.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 6){ + Intent intent = new Intent(Record.this, RecordCurl.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 7){ + Intent intent = new Intent(Record.this, RecordFly.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + }else if(select_num == 8){ + Intent intent = new Intent(Record.this, RecordTriceps.class); + if (select_time.equals("1분")) { + intent.putExtra("time", totalTimesInMillis[0]); + } else if (select_time.equals("2분")) { + intent.putExtra("time", totalTimesInMillis[1]); + } else if (select_time.equals("3분")) { + intent.putExtra("time", totalTimesInMillis[2]); + } + startActivity(intent); + finish(); + } + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + public void premiumCheck(){ + if(user == null){ + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String grade = document.getString("grade"); + if (grade == null) grade = "일반"; + + if(grade.equals("프리미엄")){ + customized.setVisibility(View.VISIBLE); + premiumMessage[0].setVisibility(View.GONE); + premiumMessage[1].setVisibility(View.GONE); + premiumMessage[2].setVisibility(View.GONE); + lockButton[0].setVisibility(View.GONE); + lockButton[1].setVisibility(View.GONE); + lockButton[2].setVisibility(View.GONE); + ex[5].setVisibility(View.VISIBLE); + ex[6].setVisibility(View.VISIBLE); + ex[7].setVisibility(View.VISIBLE); + } + } + } else { + } + } + }); + } + } +} diff --git a/app/src/main/java/com/example/newbody/RecyclerViewAdapter.java b/app/src/main/java/com/example/newbody/RecyclerViewAdapter.java new file mode 100644 index 0000000..21608cf --- /dev/null +++ b/app/src/main/java/com/example/newbody/RecyclerViewAdapter.java @@ -0,0 +1,243 @@ +package com.example.newbody; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.ListenerRegistration; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RecyclerViewAdapter extends RecyclerView.Adapter { + + private List originalUsers = new ArrayList<>(); + private List filteredUsers = new ArrayList<>(); + private FirebaseFirestore firestore; + + private FirebaseUser user; + private FirebaseAuth auth; + private String uid; + private ListenerRegistration listenerRegistration; + private boolean nameFound = true; + + public RecyclerViewAdapter() { + firestore = FirebaseFirestore.getInstance(); + // Firebase Firestore에서 데이터 변경을 감지하고 데이터를 불러오는 코드입니다. + listenerRegistration = firestore.collection("users").addSnapshotListener((querySnapshot, e) -> { + originalUsers.clear(); + + if (querySnapshot != null) { + for (QueryDocumentSnapshot snapshot : querySnapshot) { + FriendData item = snapshot.toObject(FriendData.class); + originalUsers.add(item); + } + performSearch("", ""); // 초기화 시 전체 데이터로 설정 + } + }); + + } + + // 검색 기능을 수행하는 메서드 + public void performSearch(String searchWord, String option) { + filteredUsers.clear(); + nameFound = false; + + if (searchWord == null || option == null || searchWord.isEmpty() || option.isEmpty()) { + // 검색어가 없을 때 전체 데이터를 불러옵니다. + filteredUsers.addAll(originalUsers); + } else { + for (FriendData userData : originalUsers) { + String name = userData.getName(); + String birth = userData.getBirth(); + String uid = userData.getUid(); // 친구의 고유 UID + + if (name != null && birth != null) { + // 검색 옵션에 따라 데이터를 필터링하여 추가합니다. + if (option.equals("name") && name.contains(searchWord)) { + FriendData friend = new FriendData(name, birth, uid); // 생성자에 데이터 추가 + friend.setUid(uid); + filteredUsers.add(friend); + nameFound = true; + } else if (option.equals("birth") && birth.contains(searchWord)) { + FriendData friend = new FriendData(name, birth, uid); // 생성자에 데이터 추가 + friend.setUid(uid); + filteredUsers.add(friend); + nameFound = true; + } + } + } + } + notifyDataSetChanged(); // 데이터 변경을 어댑터에 알려 화면을 갱신합니다. + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + // 아이템 뷰를 생성하는 메서드입니다. + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + FriendData user = filteredUsers.get(position); + holder.bind(user); + } + + @Override + public int getItemCount() { + // 아이템 개수를 반환합니다. + return filteredUsers.size(); + } + + public class ViewHolder extends RecyclerView.ViewHolder { + TextView name; + TextView uid; + Button btnadd; + + public ViewHolder(View view) { + super(view); + // 뷰 홀더에서 아이템 뷰의 요소들을 초기화합니다. + name = view.findViewById(R.id.name); + uid = view.findViewById(R.id.uid); + btnadd = view.findViewById(R.id.btnadd); + } + + public void bind(FriendData friend) { + // 뷰 홀더에 데이터를 바인딩하여 화면에 표시합니다. + name.setText(friend.getName()); + String maskedUID = maskUID(friend.getUid()); + uid.setText(maskedUID); + + FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); + if (currentUser != null) { + String currentUid = currentUser.getUid(); // 현재 사용자의 UID + + btnadd.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean isUserAlreadyAdded = checkIfUserAlreadyAddedByUid(currentUid, friend.getUid()); + if (isUserAlreadyAdded) { + return; + } + FirebaseFirestore db = FirebaseFirestore.getInstance(); + + // 상대방의 UID로 친구 문서를 추가 + DocumentReference friendRef = db.collection("users") + .document(friend.getUid()) // 상대방의 UID로 도큐먼트 접근 + .collection("friends") + .document(currentUid); // 사용자 정의 문서 ID + Map friendData = new HashMap<>(); + + DocumentReference currentUserDocRef = db.collection("users").document(currentUid); + currentUserDocRef.get().addOnSuccessListener(documentSnapshot -> { + if (documentSnapshot.exists()) { + String currentUserName = documentSnapshot.getString("name"); + String currentUserGender = documentSnapshot.getString("gender"); + String currentUserHeight = documentSnapshot.getString("height"); + String currentUserWeight = documentSnapshot.getString("weight"); + String currentUserBirth = documentSnapshot.getString("birth"); + String currentUserFcmToken = documentSnapshot.getString("fcmToken"); + + friendData.put("name", currentUserName); // 현재 사용자의 이름 + friendData.put("uid", currentUid); + friendData.put("gender", currentUserGender); + friendData.put("height", currentUserHeight); + friendData.put("weight", currentUserWeight); + friendData.put("birth", currentUserBirth); + friendData.put("fcmToken", currentUserFcmToken); + // 나머지 정보도 필요한 속성에 맞게 추가 + + friendRef.set(friendData) + .addOnSuccessListener(documentReference -> { + // 상대방 친구 목록에 추가 성공 처리 + }) + .addOnFailureListener(e -> { + // 상대방 친구 목록에 추가 실패 처리 + }); + + // 나의 친구 목록에 상대방을 추가 + DocumentReference myFriendRef = db.collection("users") + .document(currentUid) // 내 UID로 도큐먼트 접근 + .collection("friends") + .document(friend.getUid()); // 사용자 정의 문서 ID + Map myFriendData = new HashMap<>(); + myFriendData.put("name", friend.getName()); // 상대방의 이름 + myFriendData.put("uid", friend.getUid()); + myFriendData.put("birth", friend.getBirth()); + myFriendData.put("gender", friend.getGender()); + myFriendData.put("height", friend.getHeight()); + myFriendData.put("weight", friend.getWeight()); + myFriendData.put("fcmToken", friend.getFcmToken()); + // 나머지 정보도 필요한 속성에 맞게 추가 + + myFriendRef.set(myFriendData) + .addOnSuccessListener(documentReference -> { + // 나의 친구 목록에 추가 성공 처리 + }) + .addOnFailureListener(e -> { + // 나의 친구 목록에 추가 실패 처리 + }); + } + }).addOnFailureListener(e -> { + // 데이터 가져오기 실패 처리 + }); + } + }); + } + } + private String maskUID(String uid) { + if (uid == null || uid.length() < 6) { + return uid; // UID가 null이거나 6자리 미만일 경우 가려지지 않은 UID를 반환 + } + + String masked = uid.substring(0, 6); // 앞 4자리를 유지 + for (int i = 6; i < uid.length(); i++) { + masked += "*"; // 나머지 자리는 '*'로 대체 + } + + return masked; + } + private boolean checkIfUserAlreadyAddedByUid(String currentUid, String friendUid) { + FirebaseFirestore db = FirebaseFirestore.getInstance(); + + DocumentReference myFriendRef = db.collection("users") + .document(currentUid) // 내 UID로 도큐먼트 접근 + .collection("friends") + .document(friendUid); // 사용자의 UID를 문서 ID로 사용 + + Log.d("RecyclerViewAdapter", "Checking if user is already added…"); + + myFriendRef.get().addOnSuccessListener(documentSnapshot -> { + boolean isSuccessful = documentSnapshot.exists(); + if (isSuccessful) { + Toast.makeText(itemView.getContext(), "이미 추가된 사용자입니다.", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(itemView.getContext(), "정상적으로 추가하였습니다.", Toast.LENGTH_SHORT).show(); + } + }).addOnFailureListener(e -> { + }); + + return false; // 임시 반환값 + } + + + } +} diff --git a/app/src/main/java/com/example/newbody/RecyclerViewAdapterInvite.java b/app/src/main/java/com/example/newbody/RecyclerViewAdapterInvite.java new file mode 100644 index 0000000..636902a --- /dev/null +++ b/app/src/main/java/com/example/newbody/RecyclerViewAdapterInvite.java @@ -0,0 +1,119 @@ +package com.example.newbody; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.firebase.dynamiclinks.DynamicLink; +import com.google.firebase.dynamiclinks.FirebaseDynamicLinks; + +import java.util.ArrayList; +import java.util.List; + +public class RecyclerViewAdapterInvite extends RecyclerView.Adapter { + + private List originalUsers; + private List filteredUsers; + private Context context; + private boolean nameFound = true; + public RecyclerViewAdapterInvite(Context context, List contactList) { + this.context = context; + this.originalUsers = new ArrayList<>(contactList); // 원본 목록 초기화 + this.filteredUsers = new ArrayList<>(contactList); // 필터링된 목록 초기화 + } + + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.friendinviteitem, parent, false); + return new ViewHolder(view); + } + + // 친구초대 창에 나오는 정보 + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + FriendInviteContact contact = filteredUsers.get(position); + holder.nameTextView.setText(contact.getName()); + holder.phoneNumberTextView.setText(contact.getPhoneNumber()); + + // 초대 버튼 클릭 리스너 설정 + holder.ivtBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Log.d("RecyclerViewAdapter", "친구 초대 버튼 클릭"); + // 친구 초대 창으로 이동하는 Intent 생성 + sendInvitation(contact); + } + }); + } + // 검색 기능을 수행하는 메서드 + public void performSearch(String searchWord, String option) { + filteredUsers.clear(); + nameFound = false; + + if (searchWord == null || option == null || searchWord.isEmpty() || option.isEmpty()) { + // 검색어가 없을 때 전체 데이터를 불러옵니다. + filteredUsers.addAll(originalUsers); + } else { + for (FriendInviteContact contact : originalUsers) { + String name = contact.getName(); + + if (name != null) { + // 검색 옵션에 따라 데이터를 필터링하여 추가합니다. + if (option.equals("name") && name.contains(searchWord)) { + filteredUsers.add(contact); + nameFound = true; + } + } + } + } + notifyDataSetChanged(); // 데이터 변경을 어댑터에 알려 화면을 갱신합니다. + } + + + // 메시지 보내기 기능 + private void sendInvitation(FriendInviteContact contact) { + String phoneNumber = contact.getPhoneNumber(); + String message = "새로운 삶을 살고싶으신가요? 지금부터 시작하세요! 초보자도 쉽게 따라할수 있는 홈트레이닝 NewBody: https://newbody.page.link/mKfG"; + // SMS를 보내기 위한 Intent 생성 + Uri uri = Uri.parse("smsto:" + phoneNumber); + Intent sendIntent = new Intent(Intent.ACTION_SENDTO, uri); + sendIntent.putExtra("sms_body", message); + + if (sendIntent.resolveActivity(context.getPackageManager()) != null) { + context.startActivity(sendIntent); + Toast.makeText(context, "정상적으로 초대 메시지를 보냈습니다!", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, "메시지를 보낼 앱이 설치되어 있지 않습니다.", Toast.LENGTH_SHORT).show(); + } + } + + @Override + public int getItemCount() { + return filteredUsers.size(); + } + + public class ViewHolder extends RecyclerView.ViewHolder { + public TextView nameTextView; + public TextView phoneNumberTextView; + public Button ivtBtn; + + public ViewHolder(View itemView) { + super(itemView); + nameTextView = itemView.findViewById(R.id.name); + phoneNumberTextView = itemView.findViewById(R.id.phoneNumber); + ivtBtn = itemView.findViewById(R.id.ivtBtn); + } + } +} diff --git a/app/src/main/java/com/example/newbody/RecyclerViewAdapterPlus.java b/app/src/main/java/com/example/newbody/RecyclerViewAdapterPlus.java new file mode 100644 index 0000000..409c15e --- /dev/null +++ b/app/src/main/java/com/example/newbody/RecyclerViewAdapterPlus.java @@ -0,0 +1,219 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.RecyclerView; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.FirebaseFirestore; +import com.squareup.picasso.Picasso; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RecyclerViewAdapterPlus extends RecyclerView.Adapter { + + private List mFriendList = new ArrayList<>(); + private Map selectedItems = new HashMap<>(); + + @NonNull + @Override + public com.example.newbody.RecyclerViewAdapterPlus.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.friendplusitem, parent, false); + return new com.example.newbody.RecyclerViewAdapterPlus.ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull com.example.newbody.RecyclerViewAdapterPlus.ViewHolder holder, int position) { + holder.onBind(mFriendList.get(position)); + } + + public void setFriendList(ArrayList list) { + Collections.sort(list, (user1, user2) -> user1.getName().compareTo(user2.getName())); + this.mFriendList = list; + notifyDataSetChanged(); + } + + @Override + public int getItemCount() { + return mFriendList.size(); + } + + public class ViewHolder extends RecyclerView.ViewHolder { + TextView name; + FirebaseUser user; + TextView uid; + ImageView imageUrl; + CheckBox checkBox; + + public ViewHolder(View view) { + super(view); + name = view.findViewById(R.id.name); + uid = view.findViewById(R.id.uid); + imageUrl = view.findViewById(R.id.profile); + checkBox = view.findViewById(R.id.checkbox); + + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + int position = getAdapterPosition(); + if (position != RecyclerView.NO_POSITION) { + String uid = mFriendList.get(position).getUid(); + if (isChecked) { + selectedItems.put(uid, true); + } else { + selectedItems.remove(uid); + } + } + }); + } + + void onBind(FriendData user) { + FirebaseFirestore db = FirebaseFirestore.getInstance(); + DocumentReference userRef = db.collection("users").document(user.getUid()); + + // 기본 이미지를 미리 설정 + imageUrl.setImageResource(R.drawable.baseline_person_24); + checkBox.setChecked(selectedItems.containsKey(user.getUid())); + + userRef.get().addOnSuccessListener(documentSnapshot -> { + if (documentSnapshot.exists()) { + String imageUrl = documentSnapshot.getString("imageUrl"); + user.setImageUrl(imageUrl); + // 이미지 로딩 + if (user.getImageUrl() != null && !user.getImageUrl().isEmpty()) { + Picasso.get() + .load(user.getImageUrl()) + .placeholder(R.drawable.baseline_person_24) + .error(R.drawable.baseline_person_24) + .into(this.imageUrl); + } + } + }); + + name.setText(user.getName()); + String maskedUID = maskUID(user.getUid()); + uid.setText(maskedUID); + } + + } + private String maskUID(String uid) { + if (uid == null || uid.length() <= 6) { + return uid; // UID가 null이거나 6글자 이하일 경우 가려지지 않은 UID를 반환 + } + + String masked = uid.substring(0, 6); // 앞 6글자를 유지 + for (int i = 6; i < uid.length(); i++) { + masked += "*"; // 나머지 자리는 '*'로 대체 + } + + return masked; + } + + public void deleteSelectedItems(String currentUserUid) { + for (String uid : selectedItems.keySet()) { + // Firestore에서 데이터 삭제 처리 + deleteUserDataAndFriend(currentUserUid, uid); + } + + // 선택된 아이템 목록에서 삭제된 아이템 제거 + List newFriendList = new ArrayList<>(); + for (FriendData friend : mFriendList) { + if (!selectedItems.containsKey(friend.getUid())) { + newFriendList.add(friend); + } + } + + Log.d("NewFriendList", "New friend list after deletion: " + newFriendList.toString()); + + mFriendList = newFriendList; + selectedItems.clear(); + + notifyDataSetChanged(); // RecyclerView 갱신 추가 + + // notifyDataSetChanged() 호출 이후에도 Firebase에서 데이터를 삭제하는 로직은 그대로 두세요. + } + + private void deleteUserDataAndFriend(String currentUserUid, String friendUid) { + FirebaseFirestore db = FirebaseFirestore.getInstance(); + + // 상대방의 친구 목록에서 현재 사용자 삭제 + deleteFromFriendFriendList(friendUid, currentUserUid); + + // 선택된 아이템 목록에서 삭제된 아이템 제거 + List newFriendList = new ArrayList<>(); + for (FriendData friend : mFriendList) { + if (!selectedItems.containsKey(friend.getUid())) { + newFriendList.add(friend); + } + } + + Log.d("NewFriendList", "New friend list after deletion: " + newFriendList.toString()); + + mFriendList = newFriendList; + selectedItems.clear(); + + notifyDataSetChanged(); + } + + + private void deleteFromFriendFriendList(String friendUid, String currentUserUid) { + FirebaseFirestore db = FirebaseFirestore.getInstance(); + + // 상대방의 친구 목록에서 현재 사용자 삭제 + db.collection("users").document(friendUid) + .collection("friends") + .document(currentUserUid) + .delete() + .addOnSuccessListener(aVoid -> { + Log.d("DeleteFriendSuccess", "Friend relationship deleted successfully from friend's list."); + + // 선택된 아이템 목록에서 삭제된 아이템 제거 + List newFriendList = new ArrayList<>(); + for (FriendData friend : mFriendList) { + if (!selectedItems.containsKey(friend.getUid())) { + newFriendList.add(friend); + } + } + + Log.d("NewFriendList", "New friend list after deletion: " + newFriendList.toString()); + + mFriendList = newFriendList; + selectedItems.clear(); + + notifyDataSetChanged(); + }) + .addOnFailureListener(e -> { + Log.e("DeleteFriendFailure", "Friend relationship deletion failed from friend's list: " + e.getMessage()); + }); + + // 여기서 friendUid에 해당하는 문서를 삭제하는 로직을 추가하세요. + db.collection("users").document(currentUserUid) + .collection("friends") + .document(friendUid) + .delete() + .addOnSuccessListener(aVoid -> { + Log.d("DeleteFriendSuccess", "Friend relationship deleted successfully from user's list."); + }) + .addOnFailureListener(e -> { + Log.e("DeleteFriendFailure", "Friend relationship deletion failed from user's list: " + e.getMessage()); + }); + } + + + + +} diff --git a/app/src/main/java/com/example/newbody/Target.java b/app/src/main/java/com/example/newbody/Target.java new file mode 100644 index 0000000..66c54ed --- /dev/null +++ b/app/src/main/java/com/example/newbody/Target.java @@ -0,0 +1,581 @@ +package com.example.newbody; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.videoinfo.VideoDumbbell; +import com.example.newbody.videoinfo.VideoLegRaise; +import com.example.newbody.videoinfo.VideoPushups; +import com.example.newbody.videoinfo.VideoSide; +import com.example.newbody.videoinfo.VideoSquat; +import com.example.newbody.videoinfo.VideoWarmup; +import com.example.newbody.workout.Home_Training_WarmUp; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Target extends AppCompatActivity { + FirebaseFirestore db; + FirebaseAuth mAuth; + FirebaseUser user; + + private Button prev, change; + private boolean checkChange = true; + private RecyclerView targetRecyclerView; + private TargetAdapter adapter; + private String selectCnt; + private TextView []exName = new TextView[8]; + private Button []ex = new Button[8]; + private TextView []exNum = new TextView[8]; + private Switch []switches = new Switch[8]; + private View []premiumView = new View[3]; + private List targetList = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_target); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + user = mAuth.getCurrentUser(); + + initViews(); + premiumCheck(); + targetRecyclerView.setLayoutManager(new LinearLayoutManager(Target.this)); + + startTarget(user); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + }); + + change.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(checkChange){ + changeOn(); + checkChange = false; + }else{ + changeOff(); + checkChange = true; + } + } + }); + } + public void initViews(){ + prev = findViewById(R.id.prevButtonTarget); + change = findViewById(R.id.changeButton); + exName[0] = findViewById(R.id.ex1_name); + exName[1] = findViewById(R.id.ex2_name); + exName[2] = findViewById(R.id.ex3_name); + exName[3] = findViewById(R.id.ex4_name); + exName[4] = findViewById(R.id.ex5_name); + exName[5] = findViewById(R.id.ex6_name); + exName[6] = findViewById(R.id.ex7_name); + exName[7] = findViewById(R.id.ex8_name); + ex[0] = findViewById(R.id.ex1_cnt); + ex[1] = findViewById(R.id.ex2_cnt); + ex[2] = findViewById(R.id.ex3_cnt); + ex[3] = findViewById(R.id.ex4_cnt); + ex[4] = findViewById(R.id.ex5_cnt); + ex[5] = findViewById(R.id.ex6_cnt); + ex[6] = findViewById(R.id.ex7_cnt); + ex[7] = findViewById(R.id.ex8_cnt); + exNum[0] = findViewById(R.id.targetNum1); + exNum[1] = findViewById(R.id.targetNum2); + exNum[2] = findViewById(R.id.targetNum3); + exNum[3] = findViewById(R.id.targetNum4); + exNum[4] = findViewById(R.id.targetNum5); + exNum[5] = findViewById(R.id.targetNum6); + exNum[6] = findViewById(R.id.targetNum7); + exNum[7] = findViewById(R.id.targetNum8); + switches[0] = findViewById(R.id.switch1); + switches[1] = findViewById(R.id.switch2); + switches[2] = findViewById(R.id.switch3); + switches[3] = findViewById(R.id.switch4); + switches[4] = findViewById(R.id.switch5); + switches[5] = findViewById(R.id.switch6); + switches[6] = findViewById(R.id.switch7); + switches[7] = findViewById(R.id.switch8); + targetRecyclerView = findViewById(R.id.targetRecyclerView); + premiumView[0] = findViewById(R.id.premiumView1); + premiumView[1] = findViewById(R.id.premiumView2); + premiumView[2] = findViewById(R.id.premiumView3); + + switches[0].setVisibility(View.GONE); + switches[1].setVisibility(View.GONE); + switches[2].setVisibility(View.GONE); + switches[3].setVisibility(View.GONE); + switches[4].setVisibility(View.GONE); + switches[5].setVisibility(View.GONE); + switches[6].setVisibility(View.GONE); + switches[7].setVisibility(View.GONE); + ex[0].setVisibility(View.GONE); + ex[1].setVisibility(View.GONE); + ex[2].setVisibility(View.GONE); + ex[3].setVisibility(View.GONE); + ex[4].setVisibility(View.GONE); + ex[5].setVisibility(View.GONE); + ex[6].setVisibility(View.GONE); + ex[7].setVisibility(View.GONE); + exNum[0].setVisibility(View.VISIBLE); + exNum[1].setVisibility(View.VISIBLE); + exNum[2].setVisibility(View.VISIBLE); + exNum[3].setVisibility(View.VISIBLE); + exNum[4].setVisibility(View.VISIBLE); + exNum[5].setVisibility(View.VISIBLE); + exNum[6].setVisibility(View.VISIBLE); + exNum[7].setVisibility(View.VISIBLE); + change.setText("수정"); + } + + public void changeOff(){ + exNum[0].setText(ex[0].getText().toString()); + exNum[1].setText(ex[1].getText().toString()); + exNum[2].setText(ex[2].getText().toString()); + exNum[3].setText(ex[3].getText().toString()); + exNum[4].setText(ex[4].getText().toString()); + exNum[5].setText(ex[5].getText().toString()); + exNum[6].setText(ex[6].getText().toString()); + exNum[7].setText(ex[7].getText().toString()); + switches[0].setVisibility(View.GONE); + switches[1].setVisibility(View.GONE); + switches[2].setVisibility(View.GONE); + switches[3].setVisibility(View.GONE); + switches[4].setVisibility(View.GONE); + switches[5].setVisibility(View.GONE); + switches[6].setVisibility(View.GONE); + switches[7].setVisibility(View.GONE); + ex[0].setVisibility(View.GONE); + ex[1].setVisibility(View.GONE); + ex[2].setVisibility(View.GONE); + ex[3].setVisibility(View.GONE); + ex[4].setVisibility(View.GONE); + ex[5].setVisibility(View.GONE); + ex[6].setVisibility(View.GONE); + ex[7].setVisibility(View.GONE); + exNum[0].setVisibility(View.VISIBLE); + exNum[1].setVisibility(View.VISIBLE); + exNum[2].setVisibility(View.VISIBLE); + exNum[3].setVisibility(View.VISIBLE); + exNum[4].setVisibility(View.VISIBLE); + exNum[5].setVisibility(View.VISIBLE); + exNum[6].setVisibility(View.VISIBLE); + exNum[7].setVisibility(View.VISIBLE); + change.setText("수정"); + + saveTarget(user); + + fetchData(); + adapter = new TargetAdapter(targetList); + targetRecyclerView.setAdapter(adapter); + } + public void changeOn(){ + ex[0].setText(exNum[0].getText().toString()); + ex[1].setText(exNum[1].getText().toString()); + ex[2].setText(exNum[2].getText().toString()); + ex[3].setText(exNum[3].getText().toString()); + ex[4].setText(exNum[4].getText().toString()); + ex[5].setText(exNum[5].getText().toString()); + ex[6].setText(exNum[6].getText().toString()); + ex[7].setText(exNum[7].getText().toString()); + switches[0].setVisibility(View.VISIBLE); + switches[1].setVisibility(View.VISIBLE); + switches[2].setVisibility(View.VISIBLE); + switches[3].setVisibility(View.VISIBLE); + switches[4].setVisibility(View.VISIBLE); + switches[5].setVisibility(View.VISIBLE); + switches[6].setVisibility(View.VISIBLE); + switches[7].setVisibility(View.VISIBLE); + ex[0].setVisibility(View.VISIBLE); + ex[1].setVisibility(View.VISIBLE); + ex[2].setVisibility(View.VISIBLE); + ex[3].setVisibility(View.VISIBLE); + ex[4].setVisibility(View.VISIBLE); + ex[5].setVisibility(View.VISIBLE); + ex[6].setVisibility(View.VISIBLE); + ex[7].setVisibility(View.VISIBLE); + exNum[0].setVisibility(View.INVISIBLE); + exNum[1].setVisibility(View.INVISIBLE); + exNum[2].setVisibility(View.INVISIBLE); + exNum[3].setVisibility(View.INVISIBLE); + exNum[4].setVisibility(View.INVISIBLE); + exNum[5].setVisibility(View.INVISIBLE); + exNum[6].setVisibility(View.INVISIBLE); + exNum[7].setVisibility(View.INVISIBLE); + + for(int i = 0; i < 8; i++){ + int finalI = i; + ex[i].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showCntDialog(ex[finalI]); + } + }); + } + + change.setText("완료"); + + + } + + private void showCntDialog(Button ex) { + final String[] difficultyOptions = {"5개", "10개", "15개", "20개", "25개", "30개"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("개수 선택"); + builder.setItems(difficultyOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + selectCnt = difficultyOptions[which]; + ex.setText(selectCnt); + } + }); + builder.show(); + } + + private void startTarget(FirebaseUser user){ + + // 날짜 정보 생성 + DateFormat dateFormatTwo = new SimpleDateFormat("yyyyMMdd"); + String targetDate = dateFormatTwo.format(new Date()); + String userId = user.getUid(); + + db.collection("dailyTarget") + .whereEqualTo("date", targetDate) + .whereEqualTo("uid", userId) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @SuppressLint("SetTextI18n") + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + for (QueryDocumentSnapshot document : task.getResult()) { + // 해당 날짜의 데이터를 UI에 표시 + exNum[0].setText(document.getString(exName[0].getText().toString())); + exNum[1].setText(document.getString(exName[1].getText().toString())); + exNum[2].setText(document.getString(exName[2].getText().toString())); + exNum[3].setText(document.getString(exName[3].getText().toString())); + exNum[4].setText(document.getString(exName[4].getText().toString())); + exNum[5].setText(document.getString(exName[5].getText().toString())); + exNum[6].setText(document.getString(exName[6].getText().toString())); + exNum[7].setText(document.getString(exName[7].getText().toString())); + } + } else { + // 쿼리가 실패한 경우 에러 처리 + Log.d("Firestore", "Error getting documents: ", task.getException()); + } + } + }); + } + + private void saveTarget(FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyTarget"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + if(user != null){ + userData.put("date", currentDate); + userData.put("uid", user.getUid()); + userData.put(exName[0].getText().toString(), ex[0].getText().toString()); + userData.put(exName[1].getText().toString(), ex[1].getText().toString()); + userData.put(exName[2].getText().toString(), ex[2].getText().toString()); + userData.put(exName[3].getText().toString(), ex[3].getText().toString()); + userData.put(exName[4].getText().toString(), ex[4].getText().toString()); + userData.put(exName[5].getText().toString(), ex[5].getText().toString()); + userData.put(exName[6].getText().toString(), ex[6].getText().toString()); + userData.put(exName[7].getText().toString(), ex[7].getText().toString()); + } + + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + } + }); + } + + static class TargetItem { + String exerciseName; + int myScore; + + public TargetItem(String exerciseName, int myScore) { + this.exerciseName = exerciseName; + this.myScore = myScore; + } + } + + private void fetchData() { + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + String collection = null; + String key = null; + String exercise = null; + int ex_num = 0; + targetList.clear(); + for (int i = 0; i < switches.length; i++) { + if (switches[i].isChecked()) { + if(i == 0){ + collection = "dailySquatRecords"; + key = currentDate+"squatCount"; + exercise = "스쿼트"; + }else if(i == 1){ + collection = "dailyPushupRecords"; + key = currentDate+"pushupCount"; + exercise = "푸쉬업"; + }else if(i == 2){ + collection = "dailyDumbbellRecords"; + key = currentDate+"dumbbellCount"; + exercise = "덤벨 숄더 프레스"; + }else if(i == 3){ + collection = "dailySideRecords"; + key = currentDate+"sideCount"; + exercise = "사이드 래터럴 레이즈"; + }else if(i == 4){ + collection = "dailyLegRecords"; + key = currentDate+"legCount"; + exercise = "레그 레이즈"; + }else if(i == 5){ + collection = "dailyCurlRecords"; + key = currentDate+"CurlCount"; + exercise = "덤벨 컬"; + }else if(i == 6){ + collection = "dailyFlyRecords"; + key = currentDate+"flyCount"; + exercise = "덤벨 플라이"; + }else if(i == 7){ + collection = "dailyTricepsRecords"; + key = currentDate+"tricepsCount"; + exercise = "덤벨 트라이셉스 익스텐션"; + } + ex_num = extractNumber(exNum[i].getText().toString()); + loadSquatRecordWithDate(collection, key, exercise, ex_num); + } + } + } + private void loadSquatRecordWithDate(String collection, String date, String ex, int en){ + final String collectionName = collection; + String userId = user.getUid(); + String key = date; + + DocumentReference userRecordRef = db.collection(collectionName).document(userId); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + int score = 0; + if(document.getLong(key) != null){ + score = document.getLong(key).intValue(); + } + int scoreSet = (int) ((double)score/(double)en*100); + String ex_name = ex + " ( " + score + " / " + en + " ) "; + targetList.add(new TargetItem(ex_name, scoreSet)); + } else { + Log.d("Firestore", "No such document"); + } + adapter.notifyDataSetChanged(); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + public static int extractNumber(String input) { + Pattern pattern = Pattern.compile("\\d+"); // 숫자에 해당하는 정규식 + Matcher matcher = pattern.matcher(input); + + if (matcher.find()) { + return Integer.parseInt(matcher.group()); + } else { + return 0; // 숫자가 없을 경우 0을 반환 + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("스쿼트") || str.equals("푸쉬업") || str.equals("푸시업") || str.equals("덤벨 숄더 프레스") || str.equals("덤벨") || str.equals("덤벨숄더프레스") || + str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈") || str.equals("레그 레이즈") || + str.equals("레그레이즈") || str.equals("준비 운동") || str.equals("준비운동")){ + if(str.equals("스쿼트")){ + + }else if(str.equals("푸쉬업") || str.equals("푸시업")){ + + }else if(str.equals("덤벨 숄더 프레스") || str.equals("덤벨") || str.equals("덤벨숄더프레스")){ + + }else if(str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈")){ + + }else if(str.equals("레그 레이즈") || str.equals("레그레이즈")){ + + }else if(str.equals("준비 운동") || str.equals("준비운동")){ + + } + }else if(str.equals("수정") || str.equals("완료")) { + if(checkChange){ + changeOn(); + checkChange = false; + }else{ + changeOff(); + checkChange = true; + } + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + intent.putExtra("SELECTED_FRAGMENT_INDEX", 3); + startActivity(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + public void premiumCheck(){ + if(user == null){ + Intent intent = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(intent); + }else{ + db.collection("users").document(user.getUid()) + .get() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@androidx.annotation.NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + String grade = document.getString("grade"); + if (grade == null) grade = "일반"; + + if(grade.equals("프리미엄")){ + premiumView[0].setVisibility(View.VISIBLE); + premiumView[1].setVisibility(View.VISIBLE); + premiumView[2].setVisibility(View.VISIBLE); + } + } + } else { + } + } + }); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/TargetAdapter.java b/app/src/main/java/com/example/newbody/TargetAdapter.java new file mode 100644 index 0000000..2b7eb25 --- /dev/null +++ b/app/src/main/java/com/example/newbody/TargetAdapter.java @@ -0,0 +1,53 @@ +package com.example.newbody; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +public class TargetAdapter extends RecyclerView.Adapter{ + private List targetList; + + public TargetAdapter(List targetList) { + this.targetList = targetList; + } + + @NonNull + @Override + public TargetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.target_item, parent, false); + return new TargetViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull TargetViewHolder holder, int position) { + Target.TargetItem currentItem = targetList.get(position); + holder.targetName.setText(String.valueOf(currentItem.exerciseName)); + holder.progressBar.setProgress(currentItem.myScore); + Log.d("num", String.valueOf(currentItem.myScore)); + } + + @Override + public int getItemCount() { + return targetList.size(); + } + + static class TargetViewHolder extends RecyclerView.ViewHolder { + TextView targetName; + ProgressBar progressBar; + + public TargetViewHolder(@NonNull View itemView) { + super(itemView); + targetName = itemView.findViewById(R.id.targetName); + progressBar = itemView.findViewById(R.id.progressBar); + } + } +} diff --git a/app/src/main/java/com/example/newbody/TargetPose.java b/app/src/main/java/com/example/newbody/TargetPose.java new file mode 100644 index 0000000..55d93d5 --- /dev/null +++ b/app/src/main/java/com/example/newbody/TargetPose.java @@ -0,0 +1,36 @@ +package com.example.newbody; + +import java.util.List; +import java.util.Objects; + +public class TargetPose { + private final List targets; + + public TargetPose(List targets) { + this.targets = targets; + } + + public List getTargets() { + return targets; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TargetPose that = (TargetPose) o; + return Objects.equals(targets, that.targets); + } + + @Override + public int hashCode() { + return Objects.hash(targets); + } + + @Override + public String toString() { + return "TargetPose{" + + "targets=" + targets + + '}'; + } +} diff --git a/app/src/main/java/com/example/newbody/TargetShape.java b/app/src/main/java/com/example/newbody/TargetShape.java new file mode 100644 index 0000000..9a55785 --- /dev/null +++ b/app/src/main/java/com/example/newbody/TargetShape.java @@ -0,0 +1,60 @@ +package com.example.newbody; + +import java.util.List; +import java.util.Objects; + +public class TargetShape { + private final int firstLandmarkType; + private final int middleLandmarkType; + private final int lastLandmarkType; + private final double angle; + + public TargetShape(int firstLandmarkType, int middleLandmarkType, int lastLandmarkType, double angle) { + this.firstLandmarkType = firstLandmarkType; + this.middleLandmarkType = middleLandmarkType; + this.lastLandmarkType = lastLandmarkType; + this.angle = angle; + } + + public int getFirstLandmarkType() { + return firstLandmarkType; + } + + public int getMiddleLandmarkType() { + return middleLandmarkType; + } + + public int getLastLandmarkType() { + return lastLandmarkType; + } + + public double getAngle() { + return angle; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TargetShape that = (TargetShape) o; + return firstLandmarkType == that.firstLandmarkType && + middleLandmarkType == that.middleLandmarkType && + lastLandmarkType == that.lastLandmarkType && + Double.compare(that.angle, angle) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(firstLandmarkType, middleLandmarkType, lastLandmarkType, angle); + } + + @Override + public String toString() { + return "TargetShape{" + + "firstLandmarkType=" + firstLandmarkType + + ", middleLandmarkType=" + middleLandmarkType + + ", lastLandmarkType=" + lastLandmarkType + + ", angle=" + angle + + '}'; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/Video.java b/app/src/main/java/com/example/newbody/Video.java new file mode 100644 index 0000000..f65e8fe --- /dev/null +++ b/app/src/main/java/com/example/newbody/Video.java @@ -0,0 +1,332 @@ +package com.example.newbody; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.posture.PostureInfo; +import com.example.newbody.videoinfo.VideoDumbbell; +import com.example.newbody.videoinfo.VideoLegRaise; +import com.example.newbody.videoinfo.VideoPushups; +import com.example.newbody.videoinfo.VideoSide; +import com.example.newbody.videoinfo.VideoSquat; +import com.example.newbody.videoinfo.VideoWarmup; +import com.example.newbody.workout.Home_Training_WarmUp; + +import java.util.ArrayList; + +public class Video extends AppCompatActivity { + private String selectedDifficulty; // 난이도를 저장할 변수 + private Button difficulty, start, prev; + private View []ex = new View[6]; + private TextView[] LevelCountView = new TextView[6]; + private View warmupVideo; + private View pushupsVideo; + private View squatVideo; + private View dumbbellVideo; + private View sideVideo; + private View legraiseVideo; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + difficulty = findViewById(R.id.difficulty); + ex[0] = findViewById(R.id.ex_button1); + ex[1] = findViewById(R.id.ex_button2); + ex[2] = findViewById(R.id.ex_button3); + ex[3] = findViewById(R.id.ex_button4); + ex[4] = findViewById(R.id.ex_button5); + ex[5] = findViewById(R.id.ex_button6); + LevelCountView[0] = findViewById(R.id.levelcountview1); + LevelCountView[1] = findViewById(R.id.levelcountview2); + LevelCountView[2] = findViewById(R.id.levelcountview3); + LevelCountView[3] = findViewById(R.id.levelcountview4); + LevelCountView[4] = findViewById(R.id.levelcountview5); + LevelCountView[5] = findViewById(R.id.levelcountview6); + start = findViewById(R.id.start_b); + prev = findViewById(R.id.prevButtonTraning); + + warmupVideo = findViewById(R.id.ellipse_1); + squatVideo = findViewById(R.id.ellipse_2); + pushupsVideo = findViewById(R.id.ellipse_3); + dumbbellVideo = findViewById(R.id.ellipse_4); + sideVideo = findViewById(R.id.ellipse_5); + legraiseVideo = findViewById(R.id.ellipse_6); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + }); + + difficulty.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showDifficultyDialog(); + } + }); + + warmupVideo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), VideoWarmup.class); + startActivity(intent); + } + }); + + squatVideo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), VideoSquat.class); + startActivity(intent); + } + }); + + pushupsVideo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), VideoPushups.class); + startActivity(intent); + } + }); + + dumbbellVideo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), VideoDumbbell.class); + startActivity(intent); + } + }); + + sideVideo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), VideoSide.class); + startActivity(intent); + } + }); + + legraiseVideo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), VideoLegRaise.class); + startActivity(intent); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + + + @Override + public void onClick(View v) { + if (selectedDifficulty != null) { + + Intent intentSub1 = new Intent(Video.this, Home_Training_WarmUp.class); + intentSub1.putExtra("difficulty", selectedDifficulty); // 선택한 난이도 정보를 넘겨줌 + startActivity(intentSub1); + + } + else { + Toast.makeText(Video.this, "난이도를 먼저 선택해주세요.", Toast.LENGTH_SHORT).show(); + } + } + }); + + } + + private void showDifficultyDialog() { + final String[] difficultyOptions = {"쉬움", "보통", "어려움"}; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("난이도 선택"); + builder.setItems(difficultyOptions, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + selectedDifficulty = difficultyOptions[which]; + difficulty.setText(selectedDifficulty); + + // 선택한 난이도에 따라 시간 배열을 업데이트 + if (selectedDifficulty.equals("쉬움")) { + LevelCountView[0].setText("05:00"); // 준비운동 + LevelCountView[1].setText("15개"); // 스쿼트 + LevelCountView[2].setText("7개"); // 푸시업 + LevelCountView[3].setText("10개"); // 덤프 + LevelCountView[4].setText("15개"); // 사레레 + LevelCountView[5].setText("7개"); // 레그라이즈 + } else if (selectedDifficulty.equals("보통")) { + LevelCountView[0].setText("05:00"); // 준비운동 + LevelCountView[1].setText("20개"); // 스쿼트 + LevelCountView[2].setText("20개"); // 푸시업 + LevelCountView[3].setText("10개"); // 덤프 + LevelCountView[4].setText("25개"); // 사레레 + LevelCountView[5].setText("15개"); // 레그라이즈 + } else if (selectedDifficulty.equals("어려움")) { + LevelCountView[0].setText("05:00"); // 준비운동 + LevelCountView[1].setText("25개"); // 스쿼트 + LevelCountView[2].setText("35개"); // 푸시업 + LevelCountView[3].setText("10개"); // 덤프 + LevelCountView[4].setText("35개"); // 사레레 + LevelCountView[5].setText("20개"); // 레그라이즈 + } + } + }); + builder.show(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("스쿼트") || str.equals("푸쉬업") || str.equals("푸시업") || str.equals("덤벨 숄더 프레스") || str.equals("덤벨") || str.equals("덤벨숄더프레스") || + str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈") || str.equals("레그 레이즈") || + str.equals("레그레이즈") || str.equals("준비 운동") || str.equals("준비운동")){ + if(str.equals("스쿼트")){ + Intent intent = new Intent(getApplicationContext(), VideoSquat.class); + startActivity(intent); + }else if(str.equals("푸쉬업") || str.equals("푸시업")){ + Intent intent = new Intent(getApplicationContext(), VideoPushups.class); + startActivity(intent); + }else if(str.equals("덤벨 숄더 프레스") || str.equals("덤벨") || str.equals("덤벨숄더프레스")){ + Intent intent = new Intent(getApplicationContext(), VideoDumbbell.class); + startActivity(intent); + }else if(str.equals("사이드 레터럴 레이즈") || str.equals("사레레") || str.equals("사이드레터럴레이즈")){ + Intent intent = new Intent(getApplicationContext(), VideoSide.class); + startActivity(intent); + }else if(str.equals("레그 레이즈") || str.equals("레그레이즈")){ + Intent intent = new Intent(getApplicationContext(), VideoLegRaise.class); + startActivity(intent); + }else if(str.equals("준비 운동") || str.equals("준비운동")){ + Intent intent = new Intent(getApplicationContext(), VideoWarmup.class); + startActivity(intent); + } + }else if(str.equals("쉬움") || str.equals("보통") || str.equals("어려움")){ + difficulty.setText(str); + selectedDifficulty = difficulty.getText().toString(); + + // 선택한 난이도에 따라 시간 배열을 업데이트 + if (selectedDifficulty.equals("쉬움")) { + LevelCountView[0].setText("05:00"); // 준비운동 + LevelCountView[1].setText("15개"); // 스쿼트 + LevelCountView[2].setText("7개"); // 푸시업 + LevelCountView[3].setText("10개"); // 덤프 + LevelCountView[4].setText("15개"); // 사레레 + LevelCountView[5].setText("7개"); // 레그라이즈 + } else if (selectedDifficulty.equals("보통")) { + LevelCountView[0].setText("05:00"); // 준비운동 + LevelCountView[1].setText("20개"); // 스쿼트 + LevelCountView[2].setText("20개"); // 푸시업 + LevelCountView[3].setText("10개"); // 덤프 + LevelCountView[4].setText("25개"); // 사레레 + LevelCountView[5].setText("15개"); // 레그라이즈 + } else if (selectedDifficulty.equals("어려움")) { + LevelCountView[0].setText("05:00"); // 준비운동 + LevelCountView[1].setText("25개"); // 스쿼트 + LevelCountView[2].setText("35개"); // 푸시업 + LevelCountView[3].setText("10개"); // 덤프 + LevelCountView[4].setText("35개"); // 사레레 + LevelCountView[5].setText("20개"); // 레그라이즈 + } + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + }else if(str.equals("시작") || str.equals("운동 시작")){ + if (selectedDifficulty != null) { + + Intent intentSub1 = new Intent(Video.this, Home_Training_WarmUp.class); + intentSub1.putExtra("difficulty", selectedDifficulty); // 선택한 난이도 정보를 넘겨줌 + startActivity(intentSub1); + + } + else { + Toast.makeText(Video.this, "난이도를 먼저 선택해주세요.", Toast.LENGTH_SHORT).show(); + } + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + public void onBackPressed() { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/VoiceRecognitionService.java b/app/src/main/java/com/example/newbody/VoiceRecognitionService.java new file mode 100644 index 0000000..7f42d00 --- /dev/null +++ b/app/src/main/java/com/example/newbody/VoiceRecognitionService.java @@ -0,0 +1,146 @@ +package com.example.newbody; + +import android.app.Service; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.IBinder; +import android.speech.RecognitionListener; +import android.speech.RecognizerIntent; +import android.speech.SpeechRecognizer; +import androidx.core.content.ContextCompat; +import android.Manifest; +import android.util.Log; +import android.widget.Toast; +import androidx.annotation.Nullable; +import java.util.ArrayList; +import java.util.Locale; +import android.speech.tts.TextToSpeech; + +public class VoiceRecognitionService extends Service { + protected SpeechRecognizer mSpeechRecognizer; + protected Intent mRecognizerIntent; + private TextToSpeech mTextToSpeech; + + @Override + public void onCreate() { + super.onCreate(); + + // Check for permissions + if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + // Permission handling is more complex in a service, you might want to stop the service if you don't have permissions + stopSelf(); + return; + } + + startVoiceRecognition(); + initTTS(); + } + + private void initTTS() { + mTextToSpeech = new TextToSpeech(this, status -> { + if (status != TextToSpeech.ERROR) { + mTextToSpeech.setLanguage(Locale.KOREAN); + mTextToSpeech.setSpeechRate(0.7f); + mTextToSpeech.setPitch(1.1f); + } + }); + } + + private void startVoiceRecognition() { + mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this); + mRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + mRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, Locale.getDefault()); + mRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName()); + mRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); + mRecognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3); + + mSpeechRecognizer.setRecognitionListener(new RecognitionListener() { + @Override + public void onReadyForSpeech(Bundle params) {} + + @Override + public void onBeginningOfSpeech() {} + + @Override + public void onRmsChanged(float rmsdB) {} + + @Override + public void onBufferReceived(byte[] buffer) {} + + @Override + public void onEndOfSpeech() {} + + @Override + public void onError(int error) { + switch (error) { + case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: + case SpeechRecognizer.ERROR_NETWORK: + case SpeechRecognizer.ERROR_AUDIO: + case SpeechRecognizer.ERROR_SERVER: + case SpeechRecognizer.ERROR_CLIENT: + case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: + case SpeechRecognizer.ERROR_NO_MATCH: + case SpeechRecognizer.ERROR_RECOGNIZER_BUSY: + case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: + mSpeechRecognizer.startListening(mRecognizerIntent); + break; + default: + mSpeechRecognizer.cancel(); + mSpeechRecognizer.startListening(mRecognizerIntent); + break; + } + } + + @Override + public void onResults(Bundle results) { + ArrayList matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); + if (matches != null && matches.size() > 0) { + if (matches.contains("바디야") || matches.contains("뉴바디")) { + sendResult(1); + speakOut("네"); + } + } + new android.os.Handler().postDelayed(() -> mSpeechRecognizer.startListening(mRecognizerIntent), 2000); + } + + + @Override + public void onPartialResults(Bundle partialResults) {} + + @Override + public void onEvent(int eventType, Bundle params) {} + }); + mSpeechRecognizer.startListening(mRecognizerIntent); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; // For this use-case, we don't need binding. + } + + private void speakOut(String text) { + mTextToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, null); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mSpeechRecognizer != null) { + mSpeechRecognizer.destroy(); + } + if (mTextToSpeech != null) { + mTextToSpeech.stop(); + mTextToSpeech.shutdown(); + } + } + + private void sendResult(int resultCode) { + Intent intent = new Intent("com.example.newbody.RESULT_ACTION"); + intent.putExtra("resultCode", resultCode); + sendBroadcast(intent); + } + +} + diff --git a/app/src/main/java/com/example/newbody/YogaPosture.java b/app/src/main/java/com/example/newbody/YogaPosture.java new file mode 100644 index 0000000..26ee139 --- /dev/null +++ b/app/src/main/java/com/example/newbody/YogaPosture.java @@ -0,0 +1,184 @@ +package com.example.newbody; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.posture.PostureInfo; + +import java.util.ArrayList; + +public class YogaPosture extends AppCompatActivity { + + private View ex_start; + private View []yoga = new View[3]; + private TextView[]yogaName = new TextView[3]; + private TextView selectE; + private View catView, downDogView, cobraView; + private Button prev; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_yoga_posture); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + initViews(); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + finish(); + } + }); + + yoga[0].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(yogaName[0].getText()); + } + }); + yoga[1].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(yogaName[1].getText()); + } + }); + yoga[2].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + selectE.setText(yogaName[2].getText()); + } + }); + + ex_start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(selectE.getText().equals("운동")){ + Toast.makeText(YogaPosture.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + Intent intent = new Intent(getApplicationContext(), PostureInfo.class); + intent.putExtra("exercise", selectE.getText()); + startActivity(intent); + finish(); + } + }); + } + + public void initViews(){ + prev = findViewById(R.id.prevButtonYogaPosture); + ex_start = findViewById(R.id.start_button); + yoga[0] = findViewById(R.id.yoga_button1); + yoga[1] = findViewById(R.id.yoga_button2); + yoga[2] = findViewById(R.id.yoga_button3); + yogaName[0] = findViewById(R.id.yoga1_name); + yogaName[1] = findViewById(R.id.yoga2_name); + yogaName[2] = findViewById(R.id.yoga3_name); + selectE = findViewById(R.id.exercise_select); + catView = findViewById(R.id.catYogaView1); + downDogView = findViewById(R.id.downdogYogaView1); + cobraView = findViewById(R.id.cobraYogaView1); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("고양이") || str.equals("고양이자세") || str.equals("고양이 자세") || str.equals("다운 독") || str.equals("다운독") || str.equals("다운독 자세") || + str.equals("코브라") || str.equals("코브라자세") || str.equals("코브라 자세")){ + if(str.equals("고양이") || str.equals("고양이자세") || str.equals("고양이 자세")){ + selectE.setText(yogaName[0].getText()); + }else if(str.equals("다운 독") || str.equals("다운독") || str.equals("다운독 자세")){ + selectE.setText(yogaName[1].getText()); + }else if(str.equals("코브라") || str.equals("코브라자세") || str.equals("코브라 자세")){ + selectE.setText(yogaName[2].getText()); + } + }else if(str.equals("시작") || str.equals("운동 시작")){ + if(selectE.getText().equals("운동")){ + Toast.makeText(YogaPosture.this, "운동을 선택해주세요", Toast.LENGTH_SHORT).show(); + return; + } + Intent intent = new Intent(getApplicationContext(), PostureInfo.class); + intent.putExtra("exercise", selectE.getText()); + startActivity(intent); + finish(); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Menu.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/mainInfo/MainActivityA.java b/app/src/main/java/com/example/newbody/mainInfo/MainActivityA.java new file mode 100644 index 0000000..7160f5d --- /dev/null +++ b/app/src/main/java/com/example/newbody/mainInfo/MainActivityA.java @@ -0,0 +1,27 @@ +package com.example.newbody.mainInfo; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; + +public class MainActivityA extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_maina); + + View button = findViewById(R.id.nextbutton1); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), MainActivityB.class); + startActivity(intent); + } + }); + } +} diff --git a/app/src/main/java/com/example/newbody/mainInfo/MainActivityB.java b/app/src/main/java/com/example/newbody/mainInfo/MainActivityB.java new file mode 100644 index 0000000..a2796ab --- /dev/null +++ b/app/src/main/java/com/example/newbody/mainInfo/MainActivityB.java @@ -0,0 +1,27 @@ +package com.example.newbody.mainInfo; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; + +public class MainActivityB extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_mainb); + + View button = findViewById(R.id.nextbutton2); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), MainActivityC.class); + startActivity(intent); + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/mainInfo/MainActivityC.java b/app/src/main/java/com/example/newbody/mainInfo/MainActivityC.java new file mode 100644 index 0000000..d8e3d69 --- /dev/null +++ b/app/src/main/java/com/example/newbody/mainInfo/MainActivityC.java @@ -0,0 +1,27 @@ +package com.example.newbody.mainInfo; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; + +public class MainActivityC extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_mainc); + + View button = findViewById(R.id.nextbutton3); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), MainActivityD.class); + startActivity(intent); + } + }); + } +} diff --git a/app/src/main/java/com/example/newbody/mainInfo/MainActivityD.java b/app/src/main/java/com/example/newbody/mainInfo/MainActivityD.java new file mode 100644 index 0000000..f8e3ff0 --- /dev/null +++ b/app/src/main/java/com/example/newbody/mainInfo/MainActivityD.java @@ -0,0 +1,28 @@ +package com.example.newbody.mainInfo; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.Membership; +import com.example.newbody.R; + +public class MainActivityD extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_maind); + + View button = findViewById(R.id.nextbutton4); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Membership.class); + startActivity(intent); + } + }); + } +} diff --git a/app/src/main/java/com/example/newbody/posture/PostureCurl.java b/app/src/main/java/com/example/newbody/posture/PostureCurl.java new file mode 100644 index 0000000..2595431 --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureCurl.java @@ -0,0 +1,427 @@ +package com.example.newbody.posture; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureCurl extends AppCompatActivity { + + private boolean dumbbellStartDetected = false; + private boolean dumbbellEndDetected = false; + private boolean checkUp = false; + private boolean checkDown = false; + private boolean checkCurl = false; + private TargetPose targetCurlStartSign; + private TargetPose targetCurlEndSign; + private TargetPose targetCurlLowSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView curlPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_curl); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("덤벨 컬을 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + curlPosture = findViewById(R.id.postureCurlEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetCurlStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,150.0) + ) + ); + + targetCurlEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,50.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,50.0) + ) + ); + + targetCurlLowSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,40.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,40.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isCurlStart = isPoseMatching(pose, targetCurlStartSign); + boolean isCurlEnd = isPoseMatching(pose, targetCurlEndSign); + boolean isCurlLow = isPoseMatching(pose, targetCurlLowSign); + + if (isCurlEnd) { + curlPosture.setText("올리세요"); + if(!checkCurl){ + speakDumbbellStart(); + checkCurl = true; + } + checkDown = true; + } else if (isCurlStart) { + if (checkDown) { + curlPosture.setText("잘했습니다"); + speakDumbbellEnd(); + checkCurl = false; + } + checkDown = false; + } else if (!checkDown && !isCurlLow) { + curlPosture.setText("더 올리세요"); + } + } + + private void speakDumbbellEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakDumbbellStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureCurl.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureCurl.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureCurl.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureDumbbell.java b/app/src/main/java/com/example/newbody/posture/PostureDumbbell.java new file mode 100644 index 0000000..60755b6 --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureDumbbell.java @@ -0,0 +1,432 @@ +package com.example.newbody.posture; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureDumbbell extends AppCompatActivity { + + private boolean dumbbellStartDetected = false; + private boolean dumbbellEndDetected = false; + private boolean checkUp = false; + private boolean checkDown = false; + private boolean checkDumbbell = false; + private TargetPose targetDumbbellStartSign; + private TargetPose targetDumbbellEndSign; + private TargetPose targetDumbbellLowSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView dumbbellPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_dumbbell); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("덤벨숄더프레스를 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + dumbbellPosture = findViewById(R.id.postureDumbbellEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetDumbbellStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,150.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, 150.0 ), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, 150.0 ) + ) + ); + + targetDumbbellEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 75.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 75.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, 75.0 ), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, 75.0 ) + ) + ); + + targetDumbbellLowSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 120.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 120.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, 120.0 ), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, 120.0 ) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isDumbbellStart = isPoseMatching(pose, targetDumbbellStartSign); + boolean isDumbbellEnd = isPoseMatching(pose, targetDumbbellEndSign); + boolean isDumbbellLow = isPoseMatching(pose, targetDumbbellLowSign); + + if (isDumbbellEnd) { + dumbbellPosture.setText("올리세요"); + if(!checkDumbbell){ + speakDumbbellStart(); + checkDumbbell = true; + } + checkDown = true; + } else if (isDumbbellStart) { + if (checkDown) { + dumbbellPosture.setText("잘했습니다"); + speakDumbbellEnd(); + checkDumbbell = false; + } + checkDown = false; + } else if (!checkDown && !isDumbbellLow) { + dumbbellPosture.setText("더 내리세요"); + } + } + + private void speakDumbbellEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakDumbbellStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureDumbbell.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureDumbbell.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureDumbbell.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureFly.java b/app/src/main/java/com/example/newbody/posture/PostureFly.java new file mode 100644 index 0000000..b8f269d --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureFly.java @@ -0,0 +1,431 @@ +package com.example.newbody.posture; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureFly extends AppCompatActivity { + + private boolean dumbbellStartDetected = false; + private boolean dumbbellEndDetected = false; + private boolean checkUp = false; + private boolean checkDown = false; + private boolean checkFly = false; + private TargetPose targetFlyStartSign; + private TargetPose targetFlyEndSign; + private TargetPose targetFlyLowSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView flyPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_fly); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("덤벨 플라이을 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + flyPosture = findViewById(R.id.postureFlyEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetFlyStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,120.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,120.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.LEFT_SHOULDER,165.0), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.RIGHT_SHOULDER,165.0) + ) + ); + + targetFlyEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.LEFT_SHOULDER,80.0), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.RIGHT_SHOULDER,80.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,150.0) + ) + ); + + targetFlyLowSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.LEFT_SHOULDER,175.0), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.RIGHT_SHOULDER,175.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isFlyStart = isPoseMatching(pose, targetFlyStartSign); + boolean isFlyEnd = isPoseMatching(pose, targetFlyEndSign); + boolean isFlyLow = isPoseMatching(pose, targetFlyLowSign); + + if (isFlyEnd) { + flyPosture.setText("올리세요"); + if(!checkFly){ + speakDumbbellStart(); + checkFly = true; + } + checkDown = true; + } else if (isFlyStart) { + if (checkDown) { + flyPosture.setText("잘했습니다"); + speakDumbbellEnd(); + checkFly = false; + } + checkDown = false; + } else if (!checkDown && !isFlyLow) { + flyPosture.setText("더 내리세요"); + } + } + + private void speakDumbbellEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakDumbbellStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureFly.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureFly.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureFly.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureInfo.java b/app/src/main/java/com/example/newbody/posture/PostureInfo.java new file mode 100644 index 0000000..8ba62c3 --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureInfo.java @@ -0,0 +1,242 @@ +package com.example.newbody.posture; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.VideoView; + +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.YogaPosture; +import com.example.newbody.record.RecordSquat; +import com.example.newbody.record.RecordSquatMain; +import com.example.newbody.yoga.Cat; +import com.example.newbody.yoga.Cobra; +import com.example.newbody.yoga.DownDog; + +import java.util.ArrayList; + +public class PostureInfo extends AppCompatActivity { + + private Button start, prev; + private VideoView postureVideo; + private String exName; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_info); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonPostureInfo); + start = findViewById(R.id.startPosture); + postureVideo = findViewById(R.id.postureVideo); + + Intent intent = getIntent(); + exName = intent.getStringExtra("exercise"); + + Uri uri = null; + if (exName.equals("스쿼트")) { + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/squat"); + }else if(exName.equals("푸쉬업")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/pushups"); + }else if(exName.equals("덤벨 숄더 프레스")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbell"); + }else if(exName.equals("사이드 레터럴 레이즈")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/side"); + }else if(exName.equals("레그 레이즈")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/legraise"); + }else if(exName.equals("고양이 자세")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/cat"); + }else if(exName.equals("다운 독")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/downdog"); + }else if(exName.equals("코브라 자세")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/cobra"); + }else if(exName.equals("덤벨 컬")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbellcurl"); + }else if(exName.equals("덤벨 플라이")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbellfly"); + }else if(exName.equals("덤벨 트라이셉스 익스텐션")){ + uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbelltriceps"); + } + postureVideo.setVideoURI(uri); + + postureVideo.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + postureVideo.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + postureVideo.start(); + } + }); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = null; + if(exName.equals("고양이 자세") || exName.equals("다운 독") || exName.equals("코브라 자세")){ + intent = new Intent(getApplicationContext(), YogaPosture.class); + }else{ + intent = new Intent(getApplicationContext(), Posture.class); + } + startActivity(intent); + finish(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intentN = null; + if (exName.equals("스쿼트")) { + intentN = new Intent(getApplicationContext(), PostureSquat.class); + }else if(exName.equals("푸쉬업")){ + intentN = new Intent(getApplicationContext(), PosturePushup.class); + }else if(exName.equals("덤벨 숄더 프레스")){ + intentN = new Intent(getApplicationContext(), PostureDumbbell.class); + }else if(exName.equals("사이드 레터럴 레이즈")){ + intentN = new Intent(getApplicationContext(), PostureSide.class); + }else if(exName.equals("레그 레이즈")){ + intentN = new Intent(getApplicationContext(), PostureLeg.class); + }else if(exName.equals("고양이 자세")){ + intentN = new Intent(getApplicationContext(), Cat.class); + }else if(exName.equals("다운 독")){ + intentN = new Intent(getApplicationContext(), DownDog.class); + }else if(exName.equals("코브라 자세")){ + intentN = new Intent(getApplicationContext(), Cobra.class); + }else if(exName.equals("덤벨 컬")){ + intentN = new Intent(getApplicationContext(), PostureCurl.class); + }else if(exName.equals("덤벨 플라이")){ + intentN = new Intent(getApplicationContext(), PostureFly.class); + }else if(exName.equals("덤벨 트라이셉스 익스텐션")){ + intentN = new Intent(getApplicationContext(), PostureTriceps.class); + } + startActivity(intentN); + finish(); + } + }); + + + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intentN = null; + if (exName.equals("스쿼트")) { + intentN = new Intent(getApplicationContext(), PostureSquat.class); + }else if(exName.equals("푸쉬업")){ + intentN = new Intent(getApplicationContext(), PosturePushup.class); + }else if(exName.equals("덤벨 숄더 프레스")){ + intentN = new Intent(getApplicationContext(), PostureDumbbell.class); + }else if(exName.equals("사이드 레터럴 레이즈")){ + intentN = new Intent(getApplicationContext(), PostureSide.class); + }else if(exName.equals("레그 레이즈")){ + intentN = new Intent(getApplicationContext(), PostureLeg.class); + }else if(exName.equals("고양이 자세")){ + intentN = new Intent(getApplicationContext(), Cat.class); + }else if(exName.equals("다운 독")){ + intentN = new Intent(getApplicationContext(), DownDog.class); + }else if(exName.equals("코브라 자세")){ + intentN = new Intent(getApplicationContext(), Cobra.class); + }else if(exName.equals("덤벨 컬")){ + intentN = new Intent(getApplicationContext(), PostureCurl.class); + }else if(exName.equals("덤벨 플라이")){ + intentN = new Intent(getApplicationContext(), PostureFly.class); + }else if(exName.equals("덤벨 트라이셉스 익스텐션")){ + intentN = new Intent(getApplicationContext(), PostureTriceps.class); + } + startActivity(intentN); + finish(); + }else if(str.equals("이전")){ + Intent intent = null; + if(exName.equals("고양이 자세") || exName.equals("다운 독") || exName.equals("코브라 자세")){ + intent = new Intent(getApplicationContext(), YogaPosture.class); + }else{ + intent = new Intent(getApplicationContext(), Posture.class); + } + startActivity(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureLeg.java b/app/src/main/java/com/example/newbody/posture/PostureLeg.java new file mode 100644 index 0000000..cad4531 --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureLeg.java @@ -0,0 +1,431 @@ +package com.example.newbody.posture; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureLeg extends AppCompatActivity { + + private boolean dumbbellStartDetected = false; + private boolean dumbbellEndDetected = false; + private boolean check = false; + private boolean checkLeg = false; + private TargetPose targetLegRaiseStartSign; + private TargetPose targetLegRaiseEndSign; + private TargetPose targetLegRaiseOverSign; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView legPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_leg); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("레그레이즈를 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + legPosture = findViewById(R.id.postureLegEx); + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetLegRaiseStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,100.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,100.0) + + ) + ); + + targetLegRaiseEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 170.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 170.0) + + ) + ); + + targetLegRaiseOverSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 85.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 85.0) + + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isLegStart = isPoseMatching(pose, targetLegRaiseStartSign); + boolean isLegEnd = isPoseMatching(pose, targetLegRaiseEndSign); + boolean isLegOver = isPoseMatching(pose, targetLegRaiseOverSign); + + if (isLegEnd) { + if (check) { + legPosture.setText("잘했어요"); + speakLegEnd(); + checkLeg = false; + } + check = false; + } else if (isLegOver) { + legPosture.setText("다리를 더이상 올리지 마세요"); + } else if (!check && !isLegStart) { + legPosture.setText("다리을 더 올리세요"); + } else if (isLegStart) { + legPosture.setText("다리를 내리세요"); + if(!checkLeg){ + speakLegStart(); + checkLeg = true; + } + check = true; + } + } + + private void speakLegEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakLegStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureLeg.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureLeg.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureLeg.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PosturePushup.java b/app/src/main/java/com/example/newbody/posture/PosturePushup.java new file mode 100644 index 0000000..0a791d4 --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PosturePushup.java @@ -0,0 +1,428 @@ +package com.example.newbody.posture; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PosturePushup extends AppCompatActivity { + + private boolean check = false; + private boolean checkPushup = false; + private TargetPose targetPushupStartSign; + private TargetPose targetPushupEndSign; + private TargetPose targetPushupHipOverSign; + private TargetPose targetPushupUpSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView pushupPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_pushup); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("푸쉬업을 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + pushupPosture = findViewById(R.id.posturePushupEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetPushupStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 80.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 80.0) + ) + ); + + targetPushupEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,160.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,160.0) + ) + ); + + targetPushupHipOverSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 100.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 100.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isPushupStart = isPoseMatching(pose, targetPushupStartSign); + boolean isPushupEnd = isPoseMatching(pose, targetPushupEndSign); + boolean isPushupHipOver = isPoseMatching(pose, targetPushupHipOverSign); + + if (isPushupEnd) { + if (check) { + pushupPosture.setText("잘했어요"); + speakPushupEnd(); + checkPushup = false; + } + check = false; + } else if (isPushupStart) { + check = true; + pushupPosture.setText("올라가세요"); + if(!checkPushup){ + speakPushupStart(); + checkPushup = true; + } + } else if (isPushupHipOver) { + pushupPosture.setText("허리를 내리세요"); + } else if (!check && !isPushupStart) { + pushupPosture.setText("더 내려가세요"); + } + } + + private void speakPushupEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakPushupStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PosturePushup.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PosturePushup.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PosturePushup.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureSide.java b/app/src/main/java/com/example/newbody/posture/PostureSide.java new file mode 100644 index 0000000..58a424f --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureSide.java @@ -0,0 +1,428 @@ +package com.example.newbody.posture; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureSide extends AppCompatActivity { + + private boolean dumbbellStartDetected = false; + private boolean dumbbellEndDetected = false; + + private boolean check = false; + private boolean checkSide = false; + private TargetPose targetSideStartSign; + private TargetPose targetSideEndSign; + private TargetPose targetSideArmOverSign; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView sidePosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_side); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("사이드 래터럴 레이즈를 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + sidePosture = findViewById(R.id.postureSideEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetSideStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW,90.0), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW,90.0) + ) + ); + + targetSideEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW,20.0), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW,20.0) + ) + ); + targetSideArmOverSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW,100.0), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW,100.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isSideStart = isPoseMatching(pose, targetSideStartSign); + boolean isSideEnd = isPoseMatching(pose, targetSideEndSign); + boolean isSideOver = isPoseMatching(pose, targetSideArmOverSign); + + + if (isSideStart) { + sidePosture.setText("팔을 내리세요"); + if(!checkSide){ + speakSideStart(); + checkSide = true; + } + check = true; + } else if (isSideOver) { + sidePosture.setText("팔을 너무 올리셨습니다"); + } else if (!check && !isSideStart) { + sidePosture.setText("더 올리세요"); + } else if (isSideEnd) { + if (check) { + sidePosture.setText("잘했어요"); + speakSideEnd(); + checkSide = false; + } + } + } + + private void speakSideEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakSideStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureSide.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureSide.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureSide.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureSquat.java b/app/src/main/java/com/example/newbody/posture/PostureSquat.java new file mode 100644 index 0000000..bbaa4f2 --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureSquat.java @@ -0,0 +1,442 @@ +package com.example.newbody.posture; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.record.RecordSquatMain; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureSquat extends AppCompatActivity { + + private boolean goodMotionDetected = false; + private TargetPose targetSquatStartSign; + private TargetPose targetSquatEndSign; + private TargetPose targetSquatOverSign; + private boolean check = false; + private boolean checkSquat = false; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView squatPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_squat); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("스쿼트를 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + squatPosture = findViewById(R.id.postureSquatEx); + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + try { + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetSquatStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 60.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 60.0), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 70.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 70.0) + ) + ); + + targetSquatEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_ANKLE, 180.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_ANKLE, 180.0) + ) + ); + + targetSquatOverSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 50.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 50.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) throws InterruptedException { + Handler h = new Handler(); + + boolean isSquatStart = isPoseMatching(pose, targetSquatStartSign); + boolean isSquatEnd = isPoseMatching(pose, targetSquatEndSign); + boolean isSquatOver = isPoseMatching(pose, targetSquatOverSign); + + if (isSquatEnd) { + if (check) { + squatPosture.setText("잘했어요 다시 해볼까요?"); + speakSquatEnd(); + checkSquat = false; + } + check = false; + } else if (isSquatStart) { + check = true; + squatPosture.setText("Good Motion ! 이제 올라가세요"); + if(!checkSquat){ + speakSquatStart(); + checkSquat = true; + } + } else if (!check && !isSquatOver) { + squatPosture.setText("더 앉으세요"); + } else if (isSquatOver) { + squatPosture.setText("너무 앉으셨습니다. 다시 하세요."); + } + } + private void speakSquatEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakSquatStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureSquat.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureSquat.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureSquat.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/posture/PostureTriceps.java b/app/src/main/java/com/example/newbody/posture/PostureTriceps.java new file mode 100644 index 0000000..da9090e --- /dev/null +++ b/app/src/main/java/com/example/newbody/posture/PostureTriceps.java @@ -0,0 +1,446 @@ +package com.example.newbody.posture; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class PostureTriceps extends AppCompatActivity { + + private boolean goodMotionDetected = false; + private TargetPose targetTricepsStartSign; + private TargetPose targetTricepsEndSign; + private TargetPose targetTricepsLowSign; + private TargetPose targetNotTricepsSign; + private boolean check = false; + private boolean checkTriceps = false; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView tricepsPosture; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_posture_triceps); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("덤벨 트라이셉스 익스텐션을 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Posture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + tricepsPosture = findViewById(R.id.postureTricepsEx); + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + try { + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetTricepsStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 150.0) + ) + ); + + targetTricepsEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 40.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 40.0) + ) + ); + + targetTricepsLowSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 140.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 140.0) + ) + ); + + targetNotTricepsSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, 90), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, 90) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) throws InterruptedException { + Handler h = new Handler(); + + boolean isTricepsStart = isPoseMatching(pose, targetTricepsStartSign); + boolean isTricepsEnd = isPoseMatching(pose, targetTricepsEndSign); + boolean isTricepsLow = isPoseMatching(pose, targetTricepsLowSign); + boolean isNotTriceps = isPoseMatching(pose, targetNotTricepsSign); + + if (isTricepsEnd) { + if (check) { + tricepsPosture.setText("잘했어요 다시 해볼까요?"); + speakSquatEnd(); + checkTriceps = false; + } + check = false; + } else if (isTricepsStart) { + check = true; + tricepsPosture.setText("Good Motion ! 이제 내리세요"); + if(!checkTriceps){ + speakSquatStart(); + checkTriceps = true; + } + } else if (!checkTriceps && !isTricepsLow) { + tricepsPosture.setText("팔을 좀 더 올리세요"); + } else if (isNotTriceps) { + tricepsPosture.setText("팔을 위로 올리세요"); + } + } + private void speakSquatEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakSquatStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(PostureTriceps.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(PostureTriceps.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(PostureTriceps.this, Posture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordCurl.java b/app/src/main/java/com/example/newbody/record/RecordCurl.java new file mode 100644 index 0000000..1bc7892 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordCurl.java @@ -0,0 +1,157 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordCurl extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_curl); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonDumbbellCurl); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startDumbbellCurl); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time / 60000) + "분"); + + mVideoView = findViewById(R.id.dumbbellCurlEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbellcurl"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordCurl.this, RecordCurlMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordCurl.this, RecordCurlMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordCurlMain.java b/app/src/main/java/com/example/newbody/record/RecordCurlMain.java new file mode 100644 index 0000000..da2cc0b --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordCurlMain.java @@ -0,0 +1,656 @@ +package com.example.newbody.record; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class RecordCurlMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean curlStartDetected = false; + private boolean curlEndDetected = false; + private boolean checkCurl = false; + private long time; + private int score = 0; + private TargetPose targetCurlStartSign; + private TargetPose targetCurlEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_curl_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int)(millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveCurlScoreWithName(userName, user); + saveCurlRecordWithDate(userName, user); + } + } + } + }); + } + speakCurlResult(score); + customDialog = new CustomDialog(RecordCurlMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakCurlResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveCurlRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyCurlRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"CurlCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 기존의 스쿼트 수를 가져옵니다. + Long existingCurlCount = document.getLong(currentDate+"curlCount"); + if (existingCurlCount != null) { + int newCurlCount = existingCurlCount.intValue() + score; + userData.put(currentDate+"curlCount", newCurlCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveCurlScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countCurl1Minute"; + } else if (time == 120000) { + collectionName = "countCurl2Minute"; + } else if (time == 180000) { + collectionName = "countCurl3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long curlCountLong; + if (time == 60000) { + curlCountLong = document.getLong("countCurl1Minute"); + } else if (time == 120000) { + curlCountLong = document.getLong("countCurl2Minute"); + } else { + curlCountLong = document.getLong("countCurl3Minute"); + } + int existingCurlCount = 0; // 초기 값을 0으로 설정 + + if (curlCountLong != null) { + existingCurlCount = curlCountLong.intValue(); + } + + if (existingCurlCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetCurlStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,150.0) + ) + ); + + targetCurlEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,50.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,50.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isCurlStart = isPoseMatching(pose, targetCurlStartSign); + boolean isCurlEnd = isPoseMatching(pose, targetCurlEndSign); + + if (curlStartDetected && isCurlEnd) { + score++; + countEx.setText("개수 : " + score); + speakCurlCount(score); + curlStartDetected = false; // 다음 연속 감지를 위해 초기화 + curlEndDetected = false; + checkCurl = false; + } else if (isCurlStart) { + curlStartDetected = true; + if(!checkCurl){ + speakCurl(); + checkCurl = true; + } + } + } + + private void speakCurlCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void speakCurl() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordCurlMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordCurlMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordCurlMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordDumbbell.java b/app/src/main/java/com/example/newbody/record/RecordDumbbell.java new file mode 100644 index 0000000..f70fddf --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordDumbbell.java @@ -0,0 +1,158 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordDumbbell extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_dumbbell); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonDumbbell); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startDumbbell); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time/60000)+"분"); + + mVideoView = findViewById(R.id.dumbbellEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbell"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordDumbbell.this, RecordDumbbellMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordDumbbell.this, RecordDumbbellMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordDumbbellMain.java b/app/src/main/java/com/example/newbody/record/RecordDumbbellMain.java new file mode 100644 index 0000000..c04dbb2 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordDumbbellMain.java @@ -0,0 +1,667 @@ +package com.example.newbody.record; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.drawable.BitmapDrawable; +import android.media.Image; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; + +import com.example.newbody.R; + +public class RecordDumbbellMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean dumbbellStartDetected = false; + private boolean dumbbellEndDetected = false; + private boolean checkDumbbell = false; + private long time; + private int score = 0; + private TargetPose targetDumbbellStartSign; + private TargetPose targetDumbbellEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_dumbbell_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int)(millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveDumbbellScoreWithName(userName, user); + saveDumbbellRecordWithDate(userName, user); + } + } + } + }); + } + speakDumbbellResult(score); + customDialog = new CustomDialog(RecordDumbbellMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakDumbbellResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveDumbbellRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyDumbbellRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"dumbbellCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 기존의 스쿼트 수를 가져옵니다. + Long existingDumbbellCount = document.getLong(currentDate+"DumbbellCount"); + if (existingDumbbellCount != null) { + int newDumbbellCount = existingDumbbellCount.intValue() + score; + userData.put(currentDate+"dumbbellCount", newDumbbellCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveDumbbellScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countDumbbell1Minute"; + } else if (time == 120000) { + collectionName = "countDumbbell2Minute"; + } else if (time == 180000) { + collectionName = "countDumbbell3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long dumbbellCountLong; + if (time == 60000) { + dumbbellCountLong = document.getLong("countDumbbell1Minute"); + } else if (time == 120000) { + dumbbellCountLong = document.getLong("countDumbbell2Minute"); + } else { + dumbbellCountLong = document.getLong("countDumbbell3Minute"); + } + int existingDumbbellCount = 0; // 초기 값을 0으로 설정 + + if (dumbbellCountLong != null) { + existingDumbbellCount = dumbbellCountLong.intValue(); + } + + if (existingDumbbellCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetDumbbellStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,150.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, 150.0 ), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, 150.0 ) + ) + ); + + targetDumbbellEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 75.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 75.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, 75.0 ), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, 75.0 ) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isSquatStart = isPoseMatching(pose, targetDumbbellStartSign); + boolean isSquatEnd = isPoseMatching(pose, targetDumbbellEndSign); + + if (dumbbellStartDetected && isSquatEnd) { + score++; + countEx.setText("개수 : " + score); + speakDumbbellCount(score); + dumbbellStartDetected = false; // 다음 연속 감지를 위해 초기화 + dumbbellEndDetected = false; + checkDumbbell = false; + } else if (isSquatStart) { + dumbbellStartDetected = true; + if(!checkDumbbell){ + speakDumbbell(); + checkDumbbell = true; + } + } + } + + private void speakDumbbellCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void speakDumbbell() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordDumbbellMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordDumbbellMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordDumbbellMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordFly.java b/app/src/main/java/com/example/newbody/record/RecordFly.java new file mode 100644 index 0000000..d269cd4 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordFly.java @@ -0,0 +1,157 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordFly extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_fly); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonDumbbellFly); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startDumbbellFly); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time / 60000) + "분"); + + mVideoView = findViewById(R.id.dumbbellFlyEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbellfly"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordFly.this, RecordFlyMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordFly.this, RecordFlyMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordFlyMain.java b/app/src/main/java/com/example/newbody/record/RecordFlyMain.java new file mode 100644 index 0000000..fd75238 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordFlyMain.java @@ -0,0 +1,660 @@ +package com.example.newbody.record; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class RecordFlyMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean flyStartDetected = false; + private boolean flyEndDetected = false; + private boolean checkFly = false; + private long time; + private int score = 0; + private TargetPose targetFlyStartSign; + private TargetPose targetFlyEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_fly_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int)(millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveFlyScoreWithName(userName, user); + saveFlyRecordWithDate(userName, user); + } + } + } + }); + } + speakFlyResult(score); + customDialog = new CustomDialog(RecordFlyMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakFlyResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveFlyRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyFlyRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"flyCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 기존의 스쿼트 수를 가져옵니다. + Long existingFlyCount = document.getLong(currentDate+"flyCount"); + if (existingFlyCount != null) { + int newFlyCount = existingFlyCount.intValue() + score; + userData.put(currentDate+"flyCount", newFlyCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveFlyScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countFly1Minute"; + } else if (time == 120000) { + collectionName = "countFly2Minute"; + } else if (time == 180000) { + collectionName = "countFly3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long flyCountLong; + if (time == 60000) { + flyCountLong = document.getLong("countFly1Minute"); + } else if (time == 120000) { + flyCountLong = document.getLong("countFly2Minute"); + } else { + flyCountLong = document.getLong("countFly3Minute"); + } + int existingFlyCount = 0; // 초기 값을 0으로 설정 + + if (flyCountLong != null) { + existingFlyCount = flyCountLong.intValue(); + } + + if (existingFlyCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetFlyStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,120.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,120.0), + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.LEFT_SHOULDER,165.0), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.RIGHT_SHOULDER,165.0) + ) + ); + + targetFlyEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.LEFT_SHOULDER,80.0), + new TargetShape(PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_SHOULDER, PoseLandmark.RIGHT_SHOULDER,80.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST,150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST,150.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isFlyStart = isPoseMatching(pose, targetFlyStartSign); + boolean isFlyEnd = isPoseMatching(pose, targetFlyEndSign); + + if (flyStartDetected && isFlyEnd) { + score++; + countEx.setText("개수 : " + score); + speakFlyCount(score); + flyStartDetected = false; // 다음 연속 감지를 위해 초기화 + flyEndDetected = false; + checkFly = false; + } else if (isFlyStart) { + flyStartDetected = true; + if(!checkFly){ + speakFly(); + checkFly = true; + } + } + } + + private void speakFlyCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void speakFly() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordFlyMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordFlyMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordFlyMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordLegRaise.java b/app/src/main/java/com/example/newbody/record/RecordLegRaise.java new file mode 100644 index 0000000..f39e592 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordLegRaise.java @@ -0,0 +1,157 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordLegRaise extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_legraise); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonLegRaise); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startLegRaise); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time/60000)+"분"); + //덤벨컬 여기서부터 수정 + mVideoView = findViewById(R.id.LegRaiseEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/legraise"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordLegRaise.this, RecordLegRaiseMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordLegRaise.this, RecordLegRaiseMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordLegRaiseMain.java b/app/src/main/java/com/example/newbody/record/RecordLegRaiseMain.java new file mode 100644 index 0000000..b244453 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordLegRaiseMain.java @@ -0,0 +1,662 @@ +package com.example.newbody.record; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; + +import com.example.newbody.R; + +public class RecordLegRaiseMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean legRaiseStartDetected = false; + private boolean legRaiseEndDetected = false; + private boolean checkLeg = false; + private long time; + private int score = 0; + private TargetPose targetLegRaiseStartSign; + private TargetPose targetLegRaiseEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_legraise_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int)(millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + Map userData = new HashMap<>(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveLegScoreWithName(userName, user); + saveLegRecordWithDate(userName, user); + } + } + } + }); + } + speakLegResult(score); + customDialog = new CustomDialog(RecordLegRaiseMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakLegResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveLegRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyLegRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"legCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 기존의 스쿼트 수를 가져옵니다. + Long existingLegCount = document.getLong(currentDate+"legCount"); + if (existingLegCount != null) { + int newLegCount = existingLegCount.intValue() + score; + userData.put(currentDate+"legCount", newLegCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveLegScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countLeg1Minute"; + } else if (time == 120000) { + collectionName = "countLeg2Minute"; + } else if (time == 180000) { + collectionName = "countLeg3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long legCountLong; + if (time == 60000) { + legCountLong = document.getLong("countLeg1Minute"); + } else if (time == 120000) { + legCountLong = document.getLong("countLeg2Minute"); + } else { + legCountLong = document.getLong("countLeg3Minute"); + } + int existingLegCount = 0; // 초기 값을 0으로 설정 + + if (legCountLong != null) { + existingLegCount = legCountLong.intValue(); + } + + if (existingLegCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetLegRaiseStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,100.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,100.0) + + ) + ); + + targetLegRaiseEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 170.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 170.0) + + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isSquatStart = isPoseMatching(pose, targetLegRaiseStartSign); + boolean isSquatEnd = isPoseMatching(pose, targetLegRaiseEndSign); + + if (legRaiseStartDetected && isSquatEnd) { + score++; + countEx.setText("개수 : " + score); + speakLegCount(score); + legRaiseStartDetected = false; // 다음 연속 감지를 위해 초기화 + legRaiseEndDetected = false; + checkLeg = false; + } else if (isSquatStart) { + legRaiseStartDetected = true; + if(!checkLeg){ + speakLeg(); + checkLeg = true; + } + } + } + + private void speakLegCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void speakLeg() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordLegRaiseMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordLegRaiseMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordLegRaiseMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordPushup.java b/app/src/main/java/com/example/newbody/record/RecordPushup.java new file mode 100644 index 0000000..7f538aa --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordPushup.java @@ -0,0 +1,158 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordPushup extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_pushup); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonPushup); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startPushup); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time/60000)+"분"); + + mVideoView = findViewById(R.id.pushupEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/pushups"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordPushup.this, RecordPushupMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordPushup.this, RecordPushupMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordPushupMain.java b/app/src/main/java/com/example/newbody/record/RecordPushupMain.java new file mode 100644 index 0000000..87162c2 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordPushupMain.java @@ -0,0 +1,657 @@ +package com.example.newbody.record; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class RecordPushupMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean pushupStartDetected = false; + private boolean pushupEndDetected = false; + private boolean checkPushup = false; + private long time; + private int score = 0; + private TargetPose targetPushUpStartSign; + private TargetPose targetPushUpEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_pushup_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int)(millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + savePushupScoreWithName(userName, user); + savePushupRecordWithDate(userName, user); + } + } + } + }); + } + speakPushupResult(score); + customDialog = new CustomDialog(RecordPushupMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakPushupResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void savePushupRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyPushupRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"pushupCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long existingPushupCount = document.getLong(currentDate+"pushupCount"); + if (existingPushupCount != null) { + int newPushupCount = existingPushupCount.intValue() + score; + userData.put(currentDate+"pushupCount", newPushupCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void savePushupScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countPushup1Minute"; + } else if (time == 120000) { + collectionName = "countPushup2Minute"; + } else if (time == 180000) { + collectionName = "countPushup3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long pushupCountLong; + if (time == 60000) { + pushupCountLong = document.getLong("countPushup1Minute"); + } else if (time == 120000) { + pushupCountLong = document.getLong("countPushup2Minute"); + } else { + pushupCountLong = document.getLong("countPushup3Minute"); + } + int existingPushupCount = 0; // 초기 값을 0으로 설정 + + if (pushupCountLong != null) { + existingPushupCount = pushupCountLong.intValue(); + } + + if (existingPushupCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetPushUpStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 80.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 80.0) + ) + ); + + targetPushUpEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 160.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 160.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isPushupStart = isPoseMatching(pose, targetPushUpStartSign); + boolean isPushupEnd = isPoseMatching(pose, targetPushUpEndSign); + + if (pushupStartDetected && isPushupEnd) { + score++; + countEx.setText("개수 : " + score); + speakPushupCount(score); + pushupStartDetected = false; // 다음 연속 감지를 위해 초기화 + pushupEndDetected = false; + checkPushup = false; + } else if (isPushupStart) { + pushupStartDetected = true; + if(!checkPushup){ + speakPushup(); + checkPushup = true; + } + } + } + + private void speakPushupCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakPushup() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordPushupMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordPushupMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordPushupMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordSidelateralraise.java b/app/src/main/java/com/example/newbody/record/RecordSidelateralraise.java new file mode 100644 index 0000000..4316fd0 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordSidelateralraise.java @@ -0,0 +1,158 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordSidelateralraise extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_sidelateralraise); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonSide); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startside); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time/60000)+"분"); + + mVideoView = findViewById(R.id.sideEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/side"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordSidelateralraise.this, RecordSidelateralraiseMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordSidelateralraise.this, RecordSidelateralraiseMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordSidelateralraiseMain.java b/app/src/main/java/com/example/newbody/record/RecordSidelateralraiseMain.java new file mode 100644 index 0000000..e0e0207 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordSidelateralraiseMain.java @@ -0,0 +1,660 @@ +package com.example.newbody.record; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class RecordSidelateralraiseMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean SideStartDetected = false; + private boolean SideEndDetected = false; + private boolean checkSide = false; + private long time; + private int score = 0; + private TargetPose targetSideStartSign; + private TargetPose targetSideEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_sidelateralraise_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int) (millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveSideScoreWithName(userName, user); + saveSideRecordWithDate(userName, user); + } + } + } + }); + } + speakSideResult(score); + customDialog = new CustomDialog(RecordSidelateralraiseMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakSideResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveSideRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailySideRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"sideCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long existingSideCount = document.getLong(currentDate+"sideCount"); + if (existingSideCount != null) { + int newSideCount = existingSideCount.intValue() + score; + userData.put(currentDate+"sideCount", newSideCount); + } + } + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveSideScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countSide1Minute"; + } else if (time == 120000) { + collectionName = "countSide2Minute"; + } else if (time == 180000) { + collectionName = "countSide3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long sideCountLong; + if (time == 60000) { + sideCountLong = document.getLong("countSide1Minute"); + } else if (time == 120000) { + sideCountLong = document.getLong("countSide2Minute"); + } else { + sideCountLong = document.getLong("countSide3Minute"); + } + int existingSideCount = 0; // 초기 값을 0으로 설정 + + if (sideCountLong != null) { + existingSideCount = sideCountLong.intValue(); + } + + if (existingSideCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetSideStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, 90.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, 90.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 170.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 170.0) + ) + ); + + targetSideEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, 20.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, 20.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 170.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 170.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isSideStart = isPoseMatching(pose, targetSideStartSign); + boolean isSideEnd = isPoseMatching(pose, targetSideEndSign); + + if (SideStartDetected && isSideEnd) { + score++; + countEx.setText("개수 : " + score); + speakSideCount(score); + SideStartDetected = false; // 다음 연속 감지를 위해 초기화 + SideEndDetected = false; + checkSide = false; + } else if (isSideStart) { + SideStartDetected = true; + if(!checkSide){ + speakSide(); + checkSide = true; + } + } + } + + private void speakSideCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void speakSide() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordSidelateralraiseMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordSidelateralraiseMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordSidelateralraiseMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordSquat.java b/app/src/main/java/com/example/newbody/record/RecordSquat.java new file mode 100644 index 0000000..8ba44b0 --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordSquat.java @@ -0,0 +1,159 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.VideoView; + +import com.example.newbody.Menu; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordSquat extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_squat); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonSquat); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startSquat); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time/60000)+"분"); + + mVideoView = findViewById(R.id.squatEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/squat"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordSquat.this, RecordSquatMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordSquat.this, RecordSquatMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordSquatMain.java b/app/src/main/java/com/example/newbody/record/RecordSquatMain.java new file mode 100644 index 0000000..d494d0f --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordSquatMain.java @@ -0,0 +1,689 @@ +package com.example.newbody.record; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; + +import android.os.CountDownTimer; + +public class RecordSquatMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean squatStartDetected = false; + private boolean squatEndDetected = false; + private boolean checkSquat = false; + private boolean checkSquatOver = false; + + private long time; + private int score = 0; + private TargetPose targetSquatStartSign; + private TargetPose targetSquatEndSign; + private TargetPose targetSquatOverSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_squat_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int) (millisUntilFinished/1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveSquatScoreWithName(userName, user); + saveSquatRecordWithDate(userName, user); + } + } + } + }); + } + speakSquatResult(score); + customDialog = new CustomDialog(RecordSquatMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakSquatResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveSquatRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailySquatRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + userData.put(currentDate+"squatCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 기존의 스쿼트 수를 가져옵니다. + Long existingSquatCount = document.getLong(currentDate+"squatCount"); + if (existingSquatCount != null) { + int newSquatCount = existingSquatCount.intValue() + score; + userData.put(currentDate+"squatCount", newSquatCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveSquatScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countSquat1Minute"; + } else if (time == 120000) { + collectionName = "countSquat2Minute"; + } else if (time == 180000) { + collectionName = "countSquat3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long squatCountLong; + if (time == 60000) { + squatCountLong = document.getLong("countSquat1Minute"); + } else if (time == 120000) { + squatCountLong = document.getLong("countSquat2Minute"); + } else { + squatCountLong = document.getLong("countSquat3Minute"); + } + int existingSquatCount = 0; // 초기 값을 0으로 설정 + + if (squatCountLong != null) { + existingSquatCount = squatCountLong.intValue(); + } + + if (existingSquatCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetSquatStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 60.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 60.0), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 80.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 80.0) + ) + ); + + targetSquatEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, 180.0), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, 180.0) + ) + ); + + targetSquatOverSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 55.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 55.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + Handler h = new Handler(); + + boolean isSquatStart = isPoseMatching(pose, targetSquatStartSign); + boolean isSquatEnd = isPoseMatching(pose, targetSquatEndSign); + boolean isSquatOver = isPoseMatching(pose, targetSquatOverSign); + + if (squatStartDetected && isSquatEnd) { + if(checkSquat && !checkSquatOver) { + score++; + countEx.setText("개수 : " + score); + speakSquatCount(score); + squatStartDetected = false; // 다음 연속 감지를 위해 초기화 + squatEndDetected = false; + checkSquat = false; + } else if (!checkSquat && checkSquatOver) { + squatEndDetected = false; + squatStartDetected = false; + checkSquatOver = false; + } + } else if(isSquatOver) { + speakSquatOver(); + checkSquat = false; + checkSquatOver = true; + } else if (isSquatStart && !checkSquatOver) { + squatStartDetected = true; + if(!checkSquat){ + speakSquat(); + checkSquat = true; + checkSquatOver = false; + } + } + } + + private void speakSquatCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakSquat() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakSquatOver() { + String textToSpeak = "너무 내려갔습니다 다시하세요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordSquatMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + },ActivityCompat.getMainExecutor(RecordSquatMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordSquatMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordTriceps.java b/app/src/main/java/com/example/newbody/record/RecordTriceps.java new file mode 100644 index 0000000..7da1f7d --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordTriceps.java @@ -0,0 +1,157 @@ +package com.example.newbody.record; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class RecordTriceps extends AppCompatActivity { + + Button start, prev; + long time; + private VideoView mVideoView; + private TextView timeInput; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_triceps); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + prev = findViewById(R.id.prevButtonDumbbellTriceps); + timeInput = findViewById(R.id.timeInput); + + start = findViewById(R.id.startDumbbellTriceps); + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + timeInput.setText((time / 60000) + "분"); + + mVideoView = findViewById(R.id.dumbbellTricepsEx); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbelltriceps"); + mVideoView.setVideoURI(uri); + + prev.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + finish(); + } + }); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + start.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(RecordTriceps.this, RecordTricepsMain.class); + intent.putExtra("time", time); + startActivity(intent); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("시작") || str.equals("운동 시작")){ + Intent intent = new Intent(RecordTriceps.this, RecordTricepsMain.class); + intent.putExtra("time", time); + startActivity(intent); + }else if(str.equals("이전")){ + Intent intent = new Intent(getApplicationContext(), Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/record/RecordTricepsMain.java b/app/src/main/java/com/example/newbody/record/RecordTricepsMain.java new file mode 100644 index 0000000..fff199a --- /dev/null +++ b/app/src/main/java/com/example/newbody/record/RecordTricepsMain.java @@ -0,0 +1,656 @@ +package com.example.newbody.record; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.CustomDialog; +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.SetOptions; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class RecordTricepsMain extends AppCompatActivity { + + FirebaseFirestore db; + FirebaseAuth mAuth; + + private boolean tricepsStartDetected = false; + private boolean tricepsEndDetected = false; + private boolean checkTriceps = false; + private long time; + private int score = 0; + private TargetPose targetTricepsStartSign; + private TargetPose targetTricepsEndSign; + private CountDownTimer timer; + + private CustomDialog customDialog; + private TextToSpeech tts; + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + + TextView count, timeEx, countEx; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_triceps_main); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + db = FirebaseFirestore.getInstance(); + mAuth = FirebaseAuth.getInstance(); + + Intent intent = getIntent(); + time = intent.getLongExtra("time", 0); + + initTargetPoses(); + initViews(); + + startCountdown(5000); + } + + private void startCountdown(long duration) { + new CountDownTimer(duration, 1000) { + + public void onTick(long millisUntilFinished) { + speakCount((int)(millisUntilFinished / 1000)+1); + count.setText(String.valueOf((millisUntilFinished / 1000)+1)); + } + + public void onFinish() { + count.setText("시작!"); + speakStart(); + count.setVisibility(View.INVISIBLE); + startTimer(); + countEx.setText("개수 : " + score); + checkPermissions(); + } + + }.start(); + } + private void speakCount(int count) { + String textToSpeak = String.valueOf(count); + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakStart() { + String textToSpeak = "시작"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startTimer() { + + timer = new CountDownTimer(time, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timeEx.setText("남은 시간 : " + timeLeftFormatted); + } + + @Override + public void onFinish() { + FirebaseUser user = mAuth.getCurrentUser(); + if (user != null) { + // 사용자의 정보를 가져오는 부분 + DocumentReference userRef = db.collection("users").document(user.getUid()); + userRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 사용자의 이름을 가져옵니다. + String userName = document.getString("name"); + + // 스쿼트 점수와 사용자의 이름을 저장하는 로직 + saveTricepsScoreWithName(userName, user); + saveTricepsRecordWithDate(userName, user); + } + } + } + }); + } + speakTricepsResult(score); + customDialog = new CustomDialog(RecordTricepsMain.this + ,"시간 : " + (time/60000) + "분 \n기록 : " + score + "개"); + customDialog.show(); + } + }.start(); + } + + private void speakTricepsResult(int count) { + String textToSpeak ="총 기록은 " + count + "개 입니다. "; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void saveTricepsRecordWithDate(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName = "dailyTricepsRecords"; + + // 날짜 정보 생성 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + String currentDate = dateFormat.format(new Date()); + + userData.put(currentDate+"tricepsCount", score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + // 기존의 스쿼트 수를 가져옵니다. + Long existingTricepsCount = document.getLong(currentDate+"tricepsCount"); + if (existingTricepsCount != null) { + int newTricepsCount = existingTricepsCount.intValue() + score; + userData.put(currentDate+"tricepsCount", newTricepsCount); + } + } + // 새로운 스쿼트 수를 저장합니다. + userRecordRef.set(userData, SetOptions.merge()) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + } + + private void saveTricepsScoreWithName(String userName, FirebaseUser user){ + Map userData = new HashMap<>(); + final String collectionName; + + if (time == 60000) { + collectionName = "countTriceps1Minute"; + } else if (time == 120000) { + collectionName = "countTriceps2Minute"; + } else if (time == 180000) { + collectionName = "countTriceps3Minute"; + } else { + collectionName = ""; + } + + // userName을 추가합니다. + userData.put("name", userName); + userData.put(collectionName, score); + + DocumentReference userRecordRef = db.collection(collectionName).document(user.getUid()); + userRecordRef.get().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document.exists()) { + Long tricepsCountLong; + if (time == 60000) { + tricepsCountLong = document.getLong("countTriceps1Minute"); + } else if (time == 120000) { + tricepsCountLong = document.getLong("countTriceps2Minute"); + } else { + tricepsCountLong = document.getLong("countTriceps3Minute"); + } + int existingTricepsCount = 0; // 초기 값을 0으로 설정 + + if (tricepsCountLong != null) { + existingTricepsCount = tricepsCountLong.intValue(); + } + + if (existingTricepsCount <= score) { + userData.put(collectionName, score); + db.collection(collectionName).document(user.getUid()) + .set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid){ + // 성공적으로 업데이트했을 때의 로직 + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + // 업데이트 실패했을 때의 로직 + } + }); + } else { + Log.d("Firestore", "User's score is not higher than the existing record."); + } + } else { + // 만약 문서가 없다면, 바로 점수를 저장합니다. + userData.put(collectionName, score); + userRecordRef.set(userData) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + Log.d("Firestore", "Data successfully written!"); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@org.checkerframework.checker.nullness.qual.NonNull Exception e) { + Log.w("Firestore", "Error writing document", e); + } + }); + } + } else { + Log.d("Firestore", "Failed to get document", task.getException()); + } + } + }); + + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + count = findViewById(R.id.count); + timeEx = findViewById(R.id.timeEx); + countEx = findViewById(R.id.countEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetTricepsStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 150.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 150.0) + ) + ); + + targetTricepsEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 40.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 40.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isTricepsStart = isPoseMatching(pose, targetTricepsStartSign); + boolean isTricepsEnd = isPoseMatching(pose, targetTricepsEndSign); + + if (tricepsStartDetected && isTricepsEnd) { + score++; + countEx.setText("개수 : " + score); + speakTricepsCount(score); + tricepsStartDetected = false; // 다음 연속 감지를 위해 초기화 + tricepsEndDetected = false; + checkTriceps = false; + } else if (isTricepsStart) { + tricepsStartDetected = true; + if(!checkTriceps){ + speakTriceps(); + checkTriceps = true; + } + } + } + + private void speakTricepsCount(int count) { + String textToSpeak = count + "개"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void speakTriceps() { + double randomValue = Math.random(); + int value = (int)(randomValue*4)+1; + String textToSpeak = null; + if(value == 1){ + textToSpeak = "완벽해요"; + }else if(value == 2){ + textToSpeak = "좋아요"; + }else if(value == 3){ + textToSpeak = "훌륭해요"; + }else if(value == 4){ + textToSpeak = "잘했어요"; + } + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(RecordTricepsMain.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(RecordTricepsMain.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(RecordTricepsMain.this, Record.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onDestroy(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/videoinfo/VideoDumbbell.java b/app/src/main/java/com/example/newbody/videoinfo/VideoDumbbell.java new file mode 100644 index 0000000..1c774c3 --- /dev/null +++ b/app/src/main/java/com/example/newbody/videoinfo/VideoDumbbell.java @@ -0,0 +1,126 @@ +package com.example.newbody.videoinfo; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.record.RecordSquat; +import com.example.newbody.record.RecordSquatMain; + +import java.util.ArrayList; + +public class VideoDumbbell extends AppCompatActivity { + + private VideoView mVideoView; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_dumbbell); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mVideoView = findViewById(R.id.dumbbell); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbell"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT); + mp.start(); + } + }); + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전") || str.equals("나가기")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/videoinfo/VideoLegRaise.java b/app/src/main/java/com/example/newbody/videoinfo/VideoLegRaise.java new file mode 100644 index 0000000..1b032ce --- /dev/null +++ b/app/src/main/java/com/example/newbody/videoinfo/VideoLegRaise.java @@ -0,0 +1,125 @@ +package com.example.newbody.videoinfo; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; +import com.example.newbody.Record; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.record.RecordSquat; +import com.example.newbody.record.RecordSquatMain; + +import java.util.ArrayList; + +public class VideoLegRaise extends AppCompatActivity { + + private VideoView mVideoView; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_legraise); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mVideoView = findViewById(R.id.legraise); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/legraise"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전") || str.equals("나가기")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/videoinfo/VideoPushups.java b/app/src/main/java/com/example/newbody/videoinfo/VideoPushups.java new file mode 100644 index 0000000..35c8944 --- /dev/null +++ b/app/src/main/java/com/example/newbody/videoinfo/VideoPushups.java @@ -0,0 +1,123 @@ +package com.example.newbody.videoinfo; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class VideoPushups extends AppCompatActivity { + + private VideoView mVideoView; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_pushups); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mVideoView = findViewById(R.id.pushups); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/pushups"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT); + mp.start(); + } + }); + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전") || str.equals("나가기")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/videoinfo/VideoSide.java b/app/src/main/java/com/example/newbody/videoinfo/VideoSide.java new file mode 100644 index 0000000..baa0264 --- /dev/null +++ b/app/src/main/java/com/example/newbody/videoinfo/VideoSide.java @@ -0,0 +1,122 @@ +package com.example.newbody.videoinfo; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class VideoSide extends AppCompatActivity { + + private VideoView mVideoView; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_side); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mVideoView = findViewById(R.id.side); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/side"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전") || str.equals("나가기")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/videoinfo/VideoSquat.java b/app/src/main/java/com/example/newbody/videoinfo/VideoSquat.java new file mode 100644 index 0000000..ab56039 --- /dev/null +++ b/app/src/main/java/com/example/newbody/videoinfo/VideoSquat.java @@ -0,0 +1,123 @@ +package com.example.newbody.videoinfo; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class VideoSquat extends AppCompatActivity { + + private VideoView mVideoView; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_squat); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mVideoView = findViewById(R.id.squat); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/squat"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT); + mp.start(); + } + }); + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전") || str.equals("나가기")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/videoinfo/VideoWarmup.java b/app/src/main/java/com/example/newbody/videoinfo/VideoWarmup.java new file mode 100644 index 0000000..7f02ce5 --- /dev/null +++ b/app/src/main/java/com/example/newbody/videoinfo/VideoWarmup.java @@ -0,0 +1,156 @@ +package com.example.newbody.videoinfo; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.mainInfo.MainActivityB; + +import java.util.ArrayList; + +public class VideoWarmup extends AppCompatActivity { + + private VideoView mVideoView; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_warmup); + + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + + mVideoView = findViewById(R.id.warmup); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/warmup"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + // 비디오의 가로 세로 크기를 얻기 + int videoWidth = mp.getVideoWidth(); + int videoHeight = mp.getVideoHeight(); + + // 화면의 너비에 대한 비디오의 비율 계산 + float videoProportion = (float) videoWidth / (float) videoHeight; + + // VideoView의 너비와 높이를 얻기 + int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); + int screenHeight = getWindowManager().getDefaultDisplay().getHeight(); + + // 화면의 비율 계산 + float screenProportion = (float) screenWidth / (float) screenHeight; + + android.view.ViewGroup.LayoutParams lp = mVideoView.getLayoutParams(); + + if (videoProportion > screenProportion) { + // 비디오가 화면보다 더 넓은 경우 + lp.width = screenWidth; + lp.height = (int) ((float) screenWidth / videoProportion); + } else { + // 비디오가 화면보다 더 높은 경우 + lp.width = (int) (videoProportion * (float) screenHeight); + lp.height = screenHeight; + } + + // 계산된 너비와 높이로 VideoView의 크기를 업데이트 + mVideoView.setLayoutParams(lp); + + // 비디오를 시작합니다. + mp.start(); + } + }); + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // 동영상 재생이 완료되면 다시 시작 + mVideoView.start(); + } + }); + + + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("이전") || str.equals("나가기")){ + Intent intent = new Intent(getApplicationContext(), Video.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } + +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_End.java b/app/src/main/java/com/example/newbody/workout/Home_Training_End.java new file mode 100644 index 0000000..e05a98a --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_End.java @@ -0,0 +1,75 @@ +package com.example.newbody.workout; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.example.newbody.Home; +import com.example.newbody.R; +import com.example.newbody.Video; + +public class Home_Training_End extends AppCompatActivity { + + private TextView timerTextView; + + private CountDownTimer timer; + private long timeLeftInMillis = 10 * 1000; // 10초로 고정 + private boolean isTimerRunning; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_end); + + timerTextView = findViewById(R.id.timerTextView14); + + startTimer(); + } + + private void startTimer() { + if (!isTimerRunning) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + timeLeftInMillis = millisUntilFinished; + long seconds = millisUntilFinished / 1000; + timerTextView.setText(String.valueOf(seconds)); + } + + @Override + public void onFinish() { + moveToNextScreen(); + } + }.start(); + + isTimerRunning = true; + } + } + + private void moveToNextScreen() { + if (timer != null) { + timer.cancel(); + } + // 현재 액티비티에서 이전에 열려 있던 모든 액티비티를 종료하는 코드 + Intent intent = new Intent(getApplicationContext(), Video.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (timer != null) { + timer.cancel(); + } + } + +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Leg_Raise1.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Leg_Raise1.java new file mode 100644 index 0000000..a7d941c --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Leg_Raise1.java @@ -0,0 +1,361 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Leg_Raise1 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_leg_raise1); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView14); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/legraise"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button14); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button14); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView14); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton14); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 21 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 35 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 15개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 63 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 20개를 성공 시키세요!"); + break; + default: + timerDuration = 21 * 1000; // 기본값은 30초로 설정 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Leg_Raise1.this, Home_Training_Rest6.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Leg_Raise1.this, Home_Training_Rest9.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Leg_Raise2.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Leg_Raise2.java new file mode 100644 index 0000000..71602e3 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Leg_Raise2.java @@ -0,0 +1,363 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Leg_Raise2 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_leg_raise2); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView16); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/legraise"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button16); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button16); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView16); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton16); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 21 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 35 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 15개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 63 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 20개를 성공 시키세요!"); + break; + default: + timerDuration = 21 * 1000; // 기본값은 30초로 설정 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Leg_Raise2.this, Home_Training_Rest7.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Leg_Raise2.this, Home_Training_End.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Pushup1.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Pushup1.java new file mode 100644 index 0000000..de9e74a --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Pushup1.java @@ -0,0 +1,365 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Pushup1 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_pushup1); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView6); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/pushups"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button6); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button6); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView6); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton6); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 18 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 7개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 35 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 20개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 56 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 35개를 성공 시키세요!"); + break; + default: + timerDuration = 18 * 1000; + + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Pushup1.this, Home_Training_Rest2.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Pushup1.this, Home_Training_Rest3.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Pushup2.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Pushup2.java new file mode 100644 index 0000000..cec1827 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Pushup2.java @@ -0,0 +1,362 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Pushup2 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_pushup2); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView8); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/pushups"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button8); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button8); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView8); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton8); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 18 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 7개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 35 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 20개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 56 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 35개를 성공 시키세요!"); + break; + default: + timerDuration = 18 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Pushup2.this, Home_Training_Rest3.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Pushup2.this, Home_Training_Rest4.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest1.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest1.java new file mode 100644 index 0000000..374b899 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest1.java @@ -0,0 +1,357 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest1 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest1); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + startVideo();//반복재생 + + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button3); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button3); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView3); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton3); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + default: + timerDuration = 10 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest1.this, Home_Training_Squat1.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest1.this, Home_Training_Squat2.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest2.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest2.java new file mode 100644 index 0000000..c6614b2 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest2.java @@ -0,0 +1,354 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest2 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest2); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button5); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button5); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView5); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton5); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + default: + timerDuration = 30 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest2.this, Home_Training_Squat2.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest2.this, Home_Training_Pushup1.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest3.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest3.java new file mode 100644 index 0000000..17ac760 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest3.java @@ -0,0 +1,356 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest3 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest3); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button7); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button7); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView7); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton7); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + default: + timerDuration = 10 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest3.this, Home_Training_Pushup1.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest3.this, Home_Training_Pushup2.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest4.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest4.java new file mode 100644 index 0000000..a75e087 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest4.java @@ -0,0 +1,355 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest4 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest4); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + startVideo();//반복재생 + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button9); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button9); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView9); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton9); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + default: + timerDuration = 30 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest4.this, Home_Training_Pushup2.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest4.this, Home_Training_Shoulder_Press1.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest5.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest5.java new file mode 100644 index 0000000..c84a60c --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest5.java @@ -0,0 +1,360 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest5 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest5); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button11); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button11); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView11); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton11); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + default: + timerDuration = 10 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest5.this, Home_Training_Shoulder_Press1.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest5.this, Home_Training_Shoulder_Press2.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest6.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest6.java new file mode 100644 index 0000000..81154ea --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest6.java @@ -0,0 +1,359 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest6 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest6); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + startVideo();//반복재생 + + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button13); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button13); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView13); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton13); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + default: + timerDuration = 30 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest6.this, Home_Training_Shoulder_Press2.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest6.this, Home_Training_side_lateral_raise1.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest7.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest7.java new file mode 100644 index 0000000..0a83aad --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest7.java @@ -0,0 +1,359 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest7 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + private VoiceTask voiceTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest7); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button15); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button15); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView15); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton15); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + default: + timerDuration = 10 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest7.this, Home_Training_Leg_Raise1.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest7.this, Home_Training_side_lateral_raise2.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest8.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest8.java new file mode 100644 index 0000000..50292fe --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest8.java @@ -0,0 +1,357 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest8 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private VoiceTask voiceTask; + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest8); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button17); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button17); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView17); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton17); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 30 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 30 * 1000; // 분*초*1000 + break; + default: + timerDuration = 30 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest8.this, Home_Training_Leg_Raise2.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest8.this, Home_Training_Leg_Raise1.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Rest9.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest9.java new file mode 100644 index 0000000..0f9e2f6 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Rest9.java @@ -0,0 +1,355 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Rest9 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private VoiceTask voiceTask; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_rest9); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/rest"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button19); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button19); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView19); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton19); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 10 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 10 * 1000; // 분*초*1000 + break; + default: + timerDuration = 10 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Rest9.this, Home_Training_side_lateral_raise1.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Rest9.this, Home_Training_Leg_Raise2.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Shoulder_Press1.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Shoulder_Press1.java new file mode 100644 index 0000000..7ddfd40 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Shoulder_Press1.java @@ -0,0 +1,364 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Shoulder_Press1 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private VoiceTask voiceTask; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_shoulder_press1); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView10); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbell"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button10); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button10); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView10); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton10); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 27 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 25 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 25 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + default: + timerDuration = 27 * 1000; // 기본값은 30초로 설정 + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Shoulder_Press1.this, Home_Training_Rest4.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Shoulder_Press1.this, Home_Training_Rest5.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Shoulder_Press2.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Shoulder_Press2.java new file mode 100644 index 0000000..eebec0e --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Shoulder_Press2.java @@ -0,0 +1,366 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Shoulder_Press2 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private VoiceTask voiceTask; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_shoulder_press2); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView12); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/dumbbell"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button12); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button12); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView12); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton12); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 27 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 25 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 25 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 10개를 성공 시키세요!"); + break; + default: + timerDuration = 27 * 1000; // 기본값은 30초로 설정 + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Shoulder_Press2.this, Home_Training_Rest5.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Shoulder_Press2.this, Home_Training_Rest6.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Squat1.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Squat1.java new file mode 100644 index 0000000..4cafe09 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Squat1.java @@ -0,0 +1,367 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Squat1 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + + private VoiceTask voiceTask; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_squat1); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView2); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/squat"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button2); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button2); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView2); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton2); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 52 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 15개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 65 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 20개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 78 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 25개를 성공 시키세요!"); + break; + default: + timerDuration = 52 * 1000; // 기본값은 30초로 설정 + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Squat1.this, Home_Training_WarmUp.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Squat1.this, Home_Training_Rest1.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_Squat2.java b/app/src/main/java/com/example/newbody/workout/Home_Training_Squat2.java new file mode 100644 index 0000000..a809dd2 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_Squat2.java @@ -0,0 +1,368 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_Squat2 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + + private VoiceTask voiceTask; + private TextView CountView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_squat2); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView4); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/squat"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button4); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button4); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView4); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton4); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 52 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 15개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 65 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 20개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 78 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 25개를 성공 시키세요!"); + break; + default: + timerDuration = 52 * 1000; // 기본값은 30초로 설정 + + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_Squat2.this, Home_Training_Rest1.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + + + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_Squat2.this, Home_Training_Rest2.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_WarmUp.java b/app/src/main/java/com/example/newbody/workout/Home_Training_WarmUp.java new file mode 100644 index 0000000..a029b8d --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_WarmUp.java @@ -0,0 +1,358 @@ +package com.example.newbody.workout; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.VideoView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.example.newbody.Menu; +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.videoinfo.VideoDumbbell; +import com.example.newbody.videoinfo.VideoPushups; +import com.example.newbody.videoinfo.VideoSquat; +import com.example.newbody.videoinfo.VideoWarmup; + +import java.util.ArrayList; + +public class Home_Training_WarmUp extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + + private VoiceTask voiceTask; // VoiceTask의 인스턴스 선언 + + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_warmup); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/warmup"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 현재 액티비티 종료하여 이전 액티비티로 돌아감 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToSubActivity2(); // SubActivity2로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 5 * 60 * 1000; // 분*초*1000 + break; + case "보통": + timerDuration = 5 * 60 * 1000; // 분*초*1000 + break; + case "어려움": + timerDuration = 5 * 60 * 1000; // 분*초*1000 + break; + default: + timerDuration = 5 * 60 * 1000; + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToSubActivity2(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToSubActivity2(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + timer.cancel(); + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_WarmUp.this, Video.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + + private void moveToSubActivity2() { + + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_WarmUp.this, Home_Training_Squat1 .class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 SubActivity2로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToSubActivity2(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_side_lateral_raise1.java b/app/src/main/java/com/example/newbody/workout/Home_Training_side_lateral_raise1.java new file mode 100644 index 0000000..0cc892c --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_side_lateral_raise1.java @@ -0,0 +1,363 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_side_lateral_raise1 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private VoiceTask voiceTask; + private TextView CountView; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_side_lateral_raise1); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView18); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/side"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button18); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button18); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView18); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton18); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 52 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 15개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 68 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 25개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 73 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 35개를 성공 시키세요!"); + break; + default: + timerDuration = 52 * 1000; // 기본값은 30초로 설정 + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + }private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_side_lateral_raise1.this, Home_Training_Rest8.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_side_lateral_raise1.this,Home_Training_Rest7.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/workout/Home_Training_side_lateral_raise2.java b/app/src/main/java/com/example/newbody/workout/Home_Training_side_lateral_raise2.java new file mode 100644 index 0000000..3d1f9e9 --- /dev/null +++ b/app/src/main/java/com/example/newbody/workout/Home_Training_side_lateral_raise2.java @@ -0,0 +1,362 @@ +package com.example.newbody.workout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.speech.RecognizerIntent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.VideoView; + +import com.example.newbody.R; +import com.example.newbody.Video; +import com.example.newbody.VoiceRecognitionService; + +import java.util.ArrayList; + +public class Home_Training_side_lateral_raise2 extends AppCompatActivity { + + private Button prevButton; + private Button nextButton; + private Button timerButton; // 타이머 버튼 + private TextView timerTextView; + private TextView CountView; + private VoiceTask voiceTask; + private String selectedDifficulty; + private CountDownTimer timer; + private long timeLeftInMillis; // 타이머 남은 시간을 저장할 변수 + private boolean isTimerRunning; // 타이머가 동작 중인지 여부를 저장할 변수 + + private VideoView mVideoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home_training_side_lateral_raise2); + + Intent intentV = new Intent(this, VoiceRecognitionService.class); + startService(intentV); + + CountView = findViewById(R.id.CountView20); + + mVideoView = findViewById(R.id.videoView); + Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/side"); + mVideoView.setVideoURI(uri); + + startVideo();//반복재생 + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); + } + }); + + // 이전 액티비티로 이동하는 버튼 + prevButton = findViewById(R.id.prev_button20); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); // 이전 액티비티로 이동 + } + }); + + // 다음 액티비티로 이동하는 버튼 + nextButton = findViewById(R.id.next_button20); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + moveToHome_Training_Squaut1(); // Home_Training_Squaut1로 이동 + } + }); + + // 타이머 텍스트뷰 + timerTextView = findViewById(R.id.timerTextView20); + + // 타이머 버튼 + timerButton = findViewById(R.id.startbutton20); + timerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + } + }); + + // MainActivity로부터 선택한 난이도를 받아옴 + Intent intent = getIntent(); + selectedDifficulty = intent.getStringExtra("difficulty"); + +// 난이도 데이터가 전달되지 않은 경우 기본값으로 설정 + if (selectedDifficulty == null) { + selectedDifficulty = "쉬움"; + } + +// 타이머 자동 실행 + startTimer(); + } + + private void startTimer() { + int timerDuration; // 타이머 길이를 담을 변수 + switch (selectedDifficulty) { + case "쉬움": + timerDuration = 52 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 15개를 성공 시키세요!"); + break; + case "보통": + timerDuration = 68 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 25개를 성공 시키세요!"); + break; + case "어려움": + timerDuration = 73 * 1000; // 분*초*1000 + CountView.setText("주어진 시간 동안 35개를 성공 시키세요!"); + break; + default: + timerDuration = 52 * 1000; // 기본값은 30초로 설정 + } + + if (isTimerRunning) { + // 타이머가 이미 동작 중인 경우 + pauseTimer(); + } else { + // 타이머가 동작 중이 아닌 경우 + // 타이머가 동작하는 동안 prev 버튼과 next 버튼을 비활성화 + //prevButton.setEnabled(false); + //nextButton.setEnabled(false); + // 남은 시간이 저장되어 있으면 해당 시간부터 타이머 시작 + if (timeLeftInMillis > 0) { + timer = new CountDownTimer(timeLeftInMillis, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + prevButton.setEnabled(true); + nextButton.setEnabled(true); + timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } else { + // 저장된 시간이 없으면 새로운 타이머 시작 + timer = new CountDownTimer(timerDuration, 1000) { + @Override + public void onTick(long millisUntilFinished) { + // 남은 시간을 분과 초로 변환하여 표시 + timeLeftInMillis = millisUntilFinished; + long minutes = millisUntilFinished / 60000; + long seconds = (millisUntilFinished % 60000) / 1000; + String timeLeftFormatted = String.format("%02d:%02d", minutes, seconds); + timerTextView.setText(timeLeftFormatted); + } + + @Override + public void onFinish() { + // 타이머가 끝나면 prev 버튼과 next 버튼을 다시 활성화 + //prevButton.setEnabled(true); + //nextButton.setEnabled(true); + //timerTextView.setText("타이머 종료"); + timerButton.setText("START"); + isTimerRunning = false; + moveToHome_Training_Squaut1(); + } + }.start(); + } + + isTimerRunning = true; + timerButton.setText("PAUSE"); + } + } + private void startVideo() { + if (mVideoView != null) { + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 동영상이 끝나면 다시 재생 + mp.start(); + } + }); + + if (!mVideoView.isPlaying()) { + mVideoView.start(); + } + } + } + + private void pauseVideo() { + if (mVideoView != null && mVideoView.isPlaying()) { + mVideoView.pause(); + } + } + + private void pauseTimer() { + if (timer != null) { + timer.cancel(); + timer = null; // timer 객체 초기화 + } + isTimerRunning = false; + timerButton.setText("START"); + } + @Override + public void onBackPressed() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent prevIntent = new Intent(Home_Training_side_lateral_raise2.this, Home_Training_Rest9.class); + prevIntent.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 이전 액티비티로 전달 + startActivity(prevIntent); + finish(); + + // 이전 액티비티를 재생성하고 초기화하기 위해 다음 코드 실행 + overridePendingTransition(0, 0); + recreate(); + overridePendingTransition(0, 0); + } + + private void moveToHome_Training_Squaut1() { + // 액티비티 넘어가면 종료되면 타이머도 함께 종료 + if (timer != null) { + timer.cancel(); + } + Intent intentSub2 = new Intent(Home_Training_side_lateral_raise2.this,Home_Training_Rest8.class); + intentSub2.putExtra("difficulty", selectedDifficulty); // 선택된 난이도를 Home_Training_Squaut1로 전달 + startActivity(intentSub2); + finish(); + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + if (voiceTask != null) { // 이미 실행 중인 작업이 있다면 취소 + voiceTask.cancel(true); + } + voiceTask = new VoiceTask(); // 새로운 작업 인스턴스 생성 + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("일시정지") || str.equals("정지") || str.equals("시작") || str.equals("재시작") || str.equals("재생") || str.equals("일시 정지")){ + if (isTimerRunning) { + pauseTimer(); // 타이머 일시정지 + pauseVideo(); // 동영상 일시정지 + } else { + startTimer(); // 타이머 시작 + startVideo(); // 동영상 재생 + } + }else if(str.equals("이전")){ + onBackPressed(); + }else if(str.equals("다음")){ + moveToHome_Training_Squaut1(); + }else if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(this, Video.class); + startService(intent); + finish(); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + // 비동기 작업이 취소되었는지 확인 + if (isCancelled()) { + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + // 비동기 작업이 취소되었는지 확인 + if (!isCancelled()) { + getVoice(); + } + } + } + + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 10000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + pauseVideo(); // 동영상 일시정지 + + if (timer != null) { + timer.cancel(); + } + + if (voiceTask != null) { + voiceTask.cancel(true); // 비동기 작업 취소 + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + mVideoView.stopPlayback(); // 비디오 정지 및 리소스 해제 + + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} + diff --git a/app/src/main/java/com/example/newbody/yoga/Cat.java b/app/src/main/java/com/example/newbody/yoga/Cat.java new file mode 100644 index 0000000..2bba136 --- /dev/null +++ b/app/src/main/java/com/example/newbody/yoga/Cat.java @@ -0,0 +1,419 @@ +package com.example.newbody.yoga; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.YogaPosture; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class Cat extends AppCompatActivity { + + private boolean CatStartDetected = false; + private boolean CatEndDetected = false; + private boolean checkUp = false; + + private boolean checkCat = false; + private TargetPose targetCatStartSign; + private TargetPose targetCatEndSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView catYoga; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_yoga_cat); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("고양이 자세를 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), YogaPosture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.yogaExitButton); + catYoga = findViewById(R.id.yogaCatEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetCatStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,90.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,90.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 90.0 ), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 90.0 ) + ) + ); + + targetCatEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,50.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,50.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 60.0 ), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 60.0 ) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isCatStart = isPoseMatching(pose, targetCatStartSign); + boolean isCatEnd = isPoseMatching(pose, targetCatEndSign); + + if (isCatEnd) { + catYoga.setText("올리세요"); + if(!checkCat){ + speakDumbbellStart(); + checkCat = true; + } + } else if (isCatStart && checkCat) { + catYoga.setText("잘했습니다"); + speakDumbbellEnd(); + checkCat = false; + } else if (!checkCat) { + catYoga.setText("더 내리세요"); + } + } + + private void speakDumbbellEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakDumbbellStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(Cat.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(Cat.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(Cat.this, YogaPosture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/yoga/Cobra.java b/app/src/main/java/com/example/newbody/yoga/Cobra.java new file mode 100644 index 0000000..5da285b --- /dev/null +++ b/app/src/main/java/com/example/newbody/yoga/Cobra.java @@ -0,0 +1,420 @@ +package com.example.newbody.yoga; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.YogaPosture; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class Cobra extends AppCompatActivity { + + private boolean CatStartDetected = false; + private boolean CatEndDetected = false; + private boolean checkUp = false; + + private boolean checkDog = false; + private TargetPose targetCobraStartSign; + private TargetPose targetCobraEndSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView cobraYoga; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_yoga_cobra); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("다운 독을 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), YogaPosture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.yogaExitButton); + cobraYoga = findViewById(R.id.yogaCobraEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetCobraStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,170.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,170.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 170.0 ), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 170.0 ), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 170), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 170) + ) + ); + + targetCobraEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,140.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,140.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, 20), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, 20) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isCobraStart = isPoseMatching(pose, targetCobraStartSign); + boolean isCobraEnd = isPoseMatching(pose, targetCobraEndSign); + + if (isCobraEnd) { + cobraYoga.setText("내려가세요"); + if(!checkDog){ + speakDumbbellStart(); + checkDog = true; + } + } else if (isCobraStart && checkDog) { + cobraYoga.setText("잘했습니다"); + speakDumbbellEnd(); + checkDog = false; + } else if (!checkDog) { + cobraYoga.setText("더 올라가세요"); + } + } + + private void speakDumbbellEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakDumbbellStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(Cobra.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(Cobra.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(Cobra.this, YogaPosture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/newbody/yoga/DownDog.java b/app/src/main/java/com/example/newbody/yoga/DownDog.java new file mode 100644 index 0000000..64225fd --- /dev/null +++ b/app/src/main/java/com/example/newbody/yoga/DownDog.java @@ -0,0 +1,423 @@ +package com.example.newbody.yoga; + +import android.Manifest; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.speech.RecognizerIntent; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.camera.core.CameraSelector; +import androidx.camera.core.ImageCapture; +import androidx.camera.core.Preview; +import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; + +import com.example.newbody.PoseMatcher; +import com.example.newbody.Posture; +import com.example.newbody.R; +import com.example.newbody.TargetPose; +import com.example.newbody.TargetShape; +import com.example.newbody.VoiceRecognitionService; +import com.example.newbody.YogaPosture; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.mlkit.vision.common.InputImage; +import com.google.mlkit.vision.pose.Pose; +import com.google.mlkit.vision.pose.PoseDetection; +import com.google.mlkit.vision.pose.PoseDetector; +import com.google.mlkit.vision.pose.PoseLandmark; +import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class DownDog extends AppCompatActivity { + + private boolean CatStartDetected = false; + private boolean CatEndDetected = false; + private boolean checkUp = false; + + private boolean checkDog = false; + private TargetPose targetDownDogStartSign; + private TargetPose targetDownDogEndSign; + private TextToSpeech tts; + + + PreviewView previewView; + PoseDetector detector; + ImageView guidelineView; + ImageCapture imageCapture; + TextView downdogYoga; + + Button exit; + + Canvas guidelineCanvas; + Bitmap guidelineBmp, tempBitmap; + Paint guidePointPaint, guidePaint, transPaint; + + private final int UPDATE_TIME = 40; + private boolean isFrameBeingTested = false, canvasAlreadyClear = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_yoga_downdog); + + Intent intentS = new Intent(this, VoiceRecognitionService.class); + startService(intentS); + + tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int langResult = tts.setLanguage(Locale.KOREAN); + if (langResult == TextToSpeech.LANG_MISSING_DATA | + langResult == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "Language is not supported or missing data"); + }else { + // 피치와 속도를 조절합니다. + tts.setPitch(0.8f); // 높은 톤 + tts.setSpeechRate(0.9f); // 약간 빠른 속도 + tts.speak("다운 독을 시작합니다.", TextToSpeech.QUEUE_FLUSH, null, null); + } + } else { + Log.e("TTS", "Initialization failed"); + } + } + }); + + initTargetPoses(); + initViews(); + exit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getApplicationContext(), YogaPosture.class); + startActivity(intent); + finish(); + } + }); + checkPermissions(); + } + + private void loadGuidelines(Bitmap bmp, Pose pose){ + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + guidelineBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); + guidelineCanvas = new Canvas(guidelineBmp); + + if(transPaint == null || guidePaint == null){ + transPaint = new Paint(); + transPaint.setColor(Color.TRANSPARENT); + transPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePointPaint = new Paint(); + guidePointPaint.setColor(Color.RED); + guidePointPaint.setStrokeWidth(10f); + guidePointPaint.setStrokeCap(Paint.Cap.BUTT); + guidePointPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + guidePaint = new Paint(); + guidePaint.setColor(Color.WHITE); + guidePaint.setStrokeWidth(3f); + guidePaint.setStrokeCap(Paint.Cap.BUTT); + guidePaint.setStyle(Paint.Style.STROKE); + } + + // setting everything as transparent + guidelineCanvas.drawColor(Color.TRANSPARENT); +// guidelineCanvas.drawRect(0, 0, guidelineBmp.getWidth(), guidelineBmp.getHeight(), transPaint); + + // drawing just a rect + if(pose != null){ + for(PoseLandmark landmark : pose.getAllPoseLandmarks()){ + guidelineCanvas.drawCircle(landmark.getPosition().x, landmark.getPosition().y, 6f, guidePointPaint); + } + + // drawing lines + // TORSO + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, guidePaint); + + //limbs + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_WRIST).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST).getPosition().y, guidePaint); + // + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_HIP).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE).getPosition().y, guidePaint); + + //MOUTH + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EAR).getPosition().y, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.LEFT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + guidelineCanvas.drawLine(pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().x, pose.getPoseLandmark(PoseLandmark.RIGHT_EYE).getPosition().y, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().x, pose.getPoseLandmark(PoseLandmark.NOSE).getPosition().y, guidePaint); + canvasAlreadyClear = false; + }else{ + canvasAlreadyClear = true; + } + + guidelineView.invalidate(); + guidelineView.setImageBitmap(guidelineBmp); + Log.d("debugg", "New Guidelines Drawn"); + } + }); + + } + + private void initViews(){ + previewView = findViewById(R.id.viewFinder); + guidelineView = findViewById(R.id.canvas); + exit = findViewById(R.id.exitButton); + downdogYoga = findViewById(R.id.postureDowndogEx); + } + + private void runTest(){ + if(detector == null){ + AccuratePoseDetectorOptions options = new AccuratePoseDetectorOptions.Builder().setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE).build(); + detector = PoseDetection.getClient(options); + } + + tempBitmap = previewView.getBitmap(); + if(previewView.getBitmap() == null){ + return; + } + + isFrameBeingTested = true; + detector.process(InputImage.fromBitmap(tempBitmap, 0)).addOnCompleteListener(new OnCompleteListener() { + + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Pose pose = task.getResult(); + handlePoseDetection(pose); // 포즈 감지 후 적절한 동작 처리 + List landmarks = pose.getAllPoseLandmarks(); + Log.d("debugg", "Landmarks found : " + landmarks.size()); + if(landmarks.size() == 0){ + isFrameBeingTested = false; + if(!canvasAlreadyClear) + loadGuidelines(tempBitmap, null); + return; + } + + loadGuidelines(tempBitmap, pose); + isFrameBeingTested = false; + }else{ + Log.e("debugg", "Error in test", task.getException()); + loadGuidelines(tempBitmap, null); + isFrameBeingTested = false; + } + } + }); + } + + private void initTargetPoses() { + targetDownDogStartSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,170.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,170.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 170.0 ), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 170.0 ), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 170), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 170) + ) + ); + + targetDownDogEndSign = new TargetPose( + Arrays.asList( + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE,70.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE,70.0), + new TargetShape(PoseLandmark.RIGHT_HIP, PoseLandmark.RIGHT_KNEE, PoseLandmark.RIGHT_ANKLE, 170.0 ), + new TargetShape(PoseLandmark.LEFT_HIP, PoseLandmark.LEFT_KNEE, PoseLandmark.LEFT_ANKLE, 170.0 ), + new TargetShape(PoseLandmark.RIGHT_SHOULDER, PoseLandmark.RIGHT_ELBOW, PoseLandmark.RIGHT_WRIST, 170.0), + new TargetShape(PoseLandmark.LEFT_SHOULDER, PoseLandmark.LEFT_ELBOW, PoseLandmark.LEFT_WRIST, 170.0) + ) + ); + } + + private boolean isPoseMatching(Pose pose, TargetPose targetPose) { + PoseMatcher matcher = new PoseMatcher(); // PoseMatcher 객체 생성. 이전에 제공된 코드에서 제공된 것처럼 생성해야 합니다. + return matcher.match(pose, targetPose); + } + + private void handlePoseDetection(Pose pose) { + boolean isDownDogStart = isPoseMatching(pose, targetDownDogStartSign); + boolean isDownDogEnd = isPoseMatching(pose, targetDownDogEndSign); + + if (isDownDogEnd) { + downdogYoga.setText("올리세요"); + if(!checkDog){ + speakDumbbellStart(); + checkDog = true; + } + } else if (isDownDogStart && checkDog) { + downdogYoga.setText("잘했습니다"); + speakDumbbellEnd(); + checkDog = false; + } else if (!checkDog) { + downdogYoga.setText("더 내리세요"); + } + } + + private void speakDumbbellEnd() { + String textToSpeak ="잘했어요 다시 해볼까요?"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + private void speakDumbbellStart() { + String textToSpeak ="좋아요"; + tts.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, null, null); + } + + private void startAnalysis(){ + Handler handler = new Handler(getMainLooper()); + + handler.post(new Runnable() { + @Override + public void run() { + if(!isFrameBeingTested){ + runTest(); + } + handler.postDelayed(this, UPDATE_TIME); + } + }); + } + + private void startInit(){ + ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); + cameraProviderFuture.addListener(new Runnable() { + @Override + public void run() { + try { + ProcessCameraProvider provider = cameraProviderFuture.get(); + + Preview preview = new Preview.Builder().build(); + preview.setSurfaceProvider(previewView.createSurfaceProvider()); + imageCapture = new ImageCapture.Builder().build(); + + provider.unbindAll(); + provider.bindToLifecycle(DownDog.this, CameraSelector.DEFAULT_FRONT_CAMERA, preview); + + startAnalysis(); + } catch (Exception e) { + Log.e("debugg", "Error Getting camera Provider", e); + } + } + }, ActivityCompat.getMainExecutor(DownDog.this)); + } + + private void checkPermissions(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 455); + }else{ + startInit(); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == 455) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } else { + startInit(); + } + } + } + + private BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED); + if (resultCode == 1) { + VoiceTask voiceTask = new VoiceTask(); + voiceTask.execute(); + } + } + }; + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == 2 && resultCode == Activity.RESULT_OK) { + ArrayList results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + String str = results.get(0); + if(str.equals("나가기") || str.equals("종료")){ + Intent intent = new Intent(DownDog.this, YogaPosture.class); + startActivity(intent); + } + } + } + + private void restartVoiceRecognitionService() { + Intent intent = new Intent(this, VoiceRecognitionService.class); + startService(intent); + } + + public class VoiceTask extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + getVoice(); + } + } + + private void getVoice() { + Intent intent = new Intent(); + intent.setAction(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + String language = "ko-KR"; + intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); + intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 2000); + startActivityForResult(intent, 2); + } + + @Override + protected void onResume() { + super.onResume(); + // 브로드캐스트 리시버 등록 + registerReceiver(receiver, new IntentFilter("com.example.newbody.RESULT_ACTION")); + } + + @Override + protected void onPause() { + super.onPause(); + // 브로드캐스트 리시버 등록 해제 + unregisterReceiver(receiver); + } +} \ No newline at end of file diff --git a/app/src/main/newbody_logo-playstore.png b/app/src/main/newbody_logo-playstore.png new file mode 100644 index 0000000..5f0b8cb Binary files /dev/null and b/app/src/main/newbody_logo-playstore.png differ diff --git a/app/src/main/res/drawable/baseline_access_alarm_24.xml b/app/src/main/res/drawable/baseline_access_alarm_24.xml new file mode 100644 index 0000000..5e68fa8 --- /dev/null +++ b/app/src/main/res/drawable/baseline_access_alarm_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_article_24.xml b/app/src/main/res/drawable/baseline_article_24.xml new file mode 100644 index 0000000..b9c3675 --- /dev/null +++ b/app/src/main/res/drawable/baseline_article_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_assessment_24.xml b/app/src/main/res/drawable/baseline_assessment_24.xml new file mode 100644 index 0000000..c278913 --- /dev/null +++ b/app/src/main/res/drawable/baseline_assessment_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_attach_money_24.xml b/app/src/main/res/drawable/baseline_attach_money_24.xml new file mode 100644 index 0000000..bef7f3e --- /dev/null +++ b/app/src/main/res/drawable/baseline_attach_money_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_calendar_month_24.xml b/app/src/main/res/drawable/baseline_calendar_month_24.xml new file mode 100644 index 0000000..b89360f --- /dev/null +++ b/app/src/main/res/drawable/baseline_calendar_month_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_check_box_24.xml b/app/src/main/res/drawable/baseline_check_box_24.xml new file mode 100644 index 0000000..9bae540 --- /dev/null +++ b/app/src/main/res/drawable/baseline_check_box_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_curve.xml b/app/src/main/res/drawable/baseline_curve.xml new file mode 100644 index 0000000..1d755fc --- /dev/null +++ b/app/src/main/res/drawable/baseline_curve.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/baseline_curve1.xml b/app/src/main/res/drawable/baseline_curve1.xml new file mode 100644 index 0000000..51125a7 --- /dev/null +++ b/app/src/main/res/drawable/baseline_curve1.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_curve2.xml b/app/src/main/res/drawable/baseline_curve2.xml new file mode 100644 index 0000000..0dab144 --- /dev/null +++ b/app/src/main/res/drawable/baseline_curve2.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_curve3.xml b/app/src/main/res/drawable/baseline_curve3.xml new file mode 100644 index 0000000..9a02494 --- /dev/null +++ b/app/src/main/res/drawable/baseline_curve3.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_curve4.xml b/app/src/main/res/drawable/baseline_curve4.xml new file mode 100644 index 0000000..f76a2f6 --- /dev/null +++ b/app/src/main/res/drawable/baseline_curve4.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_email_24.xml b/app/src/main/res/drawable/baseline_email_24.xml new file mode 100644 index 0000000..f0abc2d --- /dev/null +++ b/app/src/main/res/drawable/baseline_email_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_height_24.xml b/app/src/main/res/drawable/baseline_height_24.xml new file mode 100644 index 0000000..fdc3f99 --- /dev/null +++ b/app/src/main/res/drawable/baseline_height_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_home_24.xml b/app/src/main/res/drawable/baseline_home_24.xml new file mode 100644 index 0000000..5a870f5 --- /dev/null +++ b/app/src/main/res/drawable/baseline_home_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_lock_24.xml b/app/src/main/res/drawable/baseline_lock_24.xml new file mode 100644 index 0000000..36cc0ed --- /dev/null +++ b/app/src/main/res/drawable/baseline_lock_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_lock_24_2.xml b/app/src/main/res/drawable/baseline_lock_24_2.xml new file mode 100644 index 0000000..8c9e27c --- /dev/null +++ b/app/src/main/res/drawable/baseline_lock_24_2.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_mic_none_24.xml b/app/src/main/res/drawable/baseline_mic_none_24.xml new file mode 100644 index 0000000..eefcfe6 --- /dev/null +++ b/app/src/main/res/drawable/baseline_mic_none_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_monitor_weight_24.xml b/app/src/main/res/drawable/baseline_monitor_weight_24.xml new file mode 100644 index 0000000..8a0de0b --- /dev/null +++ b/app/src/main/res/drawable/baseline_monitor_weight_24.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/baseline_person_24.xml b/app/src/main/res/drawable/baseline_person_24.xml new file mode 100644 index 0000000..98730cd --- /dev/null +++ b/app/src/main/res/drawable/baseline_person_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_person_24_2.xml b/app/src/main/res/drawable/baseline_person_24_2.xml new file mode 100644 index 0000000..6368257 --- /dev/null +++ b/app/src/main/res/drawable/baseline_person_24_2.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_person_add_alt_1_24.xml b/app/src/main/res/drawable/baseline_person_add_alt_1_24.xml new file mode 100644 index 0000000..d6f7ad8 --- /dev/null +++ b/app/src/main/res/drawable/baseline_person_add_alt_1_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_person_search_24.xml b/app/src/main/res/drawable/baseline_person_search_24.xml new file mode 100644 index 0000000..0019a4c --- /dev/null +++ b/app/src/main/res/drawable/baseline_person_search_24.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/drawable/baseline_photo_camera.xml b/app/src/main/res/drawable/baseline_photo_camera.xml new file mode 100644 index 0000000..f87ff9a --- /dev/null +++ b/app/src/main/res/drawable/baseline_photo_camera.xml @@ -0,0 +1,28 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/baseline_smartphone_24.xml b/app/src/main/res/drawable/baseline_smartphone_24.xml new file mode 100644 index 0000000..e948564 --- /dev/null +++ b/app/src/main/res/drawable/baseline_smartphone_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_supervisor_account_24.xml b/app/src/main/res/drawable/baseline_supervisor_account_24.xml new file mode 100644 index 0000000..2fe21ce --- /dev/null +++ b/app/src/main/res/drawable/baseline_supervisor_account_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_supervisor_account_24_2.xml b/app/src/main/res/drawable/baseline_supervisor_account_24_2.xml new file mode 100644 index 0000000..7c345c6 --- /dev/null +++ b/app/src/main/res/drawable/baseline_supervisor_account_24_2.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_thumb_up_24.xml b/app/src/main/res/drawable/baseline_thumb_up_24.xml new file mode 100644 index 0000000..f1ef049 --- /dev/null +++ b/app/src/main/res/drawable/baseline_thumb_up_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/blue_background.xml b/app/src/main/res/drawable/blue_background.xml new file mode 100644 index 0000000..4fbfa84 --- /dev/null +++ b/app/src/main/res/drawable/blue_background.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bmi_layout.xml b/app/src/main/res/drawable/bmi_layout.xml new file mode 100644 index 0000000..7d6248f --- /dev/null +++ b/app/src/main/res/drawable/bmi_layout.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button.xml b/app/src/main/res/drawable/button.xml new file mode 100644 index 0000000..d88dd35 --- /dev/null +++ b/app/src/main/res/drawable/button.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_black.xml b/app/src/main/res/drawable/button_black.xml new file mode 100644 index 0000000..47f79b7 --- /dev/null +++ b/app/src/main/res/drawable/button_black.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/calendar_layout.xml b/app/src/main/res/drawable/calendar_layout.xml new file mode 100644 index 0000000..af3f5dc --- /dev/null +++ b/app/src/main/res/drawable/calendar_layout.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/camera_button.xml b/app/src/main/res/drawable/camera_button.xml new file mode 100644 index 0000000..81c5736 --- /dev/null +++ b/app/src/main/res/drawable/camera_button.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/catyoga.png b/app/src/main/res/drawable/catyoga.png new file mode 100644 index 0000000..4ad980e Binary files /dev/null and b/app/src/main/res/drawable/catyoga.png differ diff --git a/app/src/main/res/drawable/cobra.png b/app/src/main/res/drawable/cobra.png new file mode 100644 index 0000000..360dd66 Binary files /dev/null and b/app/src/main/res/drawable/cobra.png differ diff --git a/app/src/main/res/drawable/curl.png b/app/src/main/res/drawable/curl.png new file mode 100644 index 0000000..d840146 Binary files /dev/null and b/app/src/main/res/drawable/curl.png differ diff --git a/app/src/main/res/drawable/custom_edittext.xml b/app/src/main/res/drawable/custom_edittext.xml new file mode 100644 index 0000000..07d6885 --- /dev/null +++ b/app/src/main/res/drawable/custom_edittext.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/custom_edittext2.xml b/app/src/main/res/drawable/custom_edittext2.xml new file mode 100644 index 0000000..368697e --- /dev/null +++ b/app/src/main/res/drawable/custom_edittext2.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/downdog.png b/app/src/main/res/drawable/downdog.png new file mode 100644 index 0000000..26decb3 Binary files /dev/null and b/app/src/main/res/drawable/downdog.png differ diff --git a/app/src/main/res/drawable/drawable_dash_line.xml b/app/src/main/res/drawable/drawable_dash_line.xml new file mode 100644 index 0000000..a394619 --- /dev/null +++ b/app/src/main/res/drawable/drawable_dash_line.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dumbbell_girl.xml b/app/src/main/res/drawable/dumbbell_girl.xml new file mode 100644 index 0000000..0b70d0d --- /dev/null +++ b/app/src/main/res/drawable/dumbbell_girl.xml @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dumbbellcurl.png b/app/src/main/res/drawable/dumbbellcurl.png new file mode 100644 index 0000000..d2dea81 Binary files /dev/null and b/app/src/main/res/drawable/dumbbellcurl.png differ diff --git a/app/src/main/res/drawable/dumbbellfly.png b/app/src/main/res/drawable/dumbbellfly.png new file mode 100644 index 0000000..cfcc579 Binary files /dev/null and b/app/src/main/res/drawable/dumbbellfly.png differ diff --git a/app/src/main/res/drawable/dumbell.png b/app/src/main/res/drawable/dumbell.png new file mode 100644 index 0000000..4b5a90c Binary files /dev/null and b/app/src/main/res/drawable/dumbell.png differ diff --git a/app/src/main/res/drawable/edittext_border.xml b/app/src/main/res/drawable/edittext_border.xml new file mode 100644 index 0000000..0886235 --- /dev/null +++ b/app/src/main/res/drawable/edittext_border.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/ellipse_1.xml b/app/src/main/res/drawable/ellipse_1.xml new file mode 100644 index 0000000..43521a1 --- /dev/null +++ b/app/src/main/res/drawable/ellipse_1.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/google.png b/app/src/main/res/drawable/google.png new file mode 100644 index 0000000..144c74e Binary files /dev/null and b/app/src/main/res/drawable/google.png differ diff --git a/app/src/main/res/drawable/home_training.jpg b/app/src/main/res/drawable/home_training.jpg new file mode 100644 index 0000000..c976cc6 Binary files /dev/null and b/app/src/main/res/drawable/home_training.jpg differ diff --git a/app/src/main/res/drawable/kakao.png b/app/src/main/res/drawable/kakao.png new file mode 100644 index 0000000..de9c4e3 Binary files /dev/null and b/app/src/main/res/drawable/kakao.png differ diff --git a/app/src/main/res/drawable/layout_default.xml b/app/src/main/res/drawable/layout_default.xml new file mode 100644 index 0000000..d0c335c --- /dev/null +++ b/app/src/main/res/drawable/layout_default.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/leg.png b/app/src/main/res/drawable/leg.png new file mode 100644 index 0000000..e957d8d Binary files /dev/null and b/app/src/main/res/drawable/leg.png differ diff --git a/app/src/main/res/drawable/leg_raise_man.xml b/app/src/main/res/drawable/leg_raise_man.xml new file mode 100644 index 0000000..652437e --- /dev/null +++ b/app/src/main/res/drawable/leg_raise_man.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/loading.png b/app/src/main/res/drawable/loading.png new file mode 100644 index 0000000..99ed0f0 Binary files /dev/null and b/app/src/main/res/drawable/loading.png differ diff --git a/app/src/main/res/drawable/login.xml b/app/src/main/res/drawable/login.xml new file mode 100644 index 0000000..b0d0ab9 --- /dev/null +++ b/app/src/main/res/drawable/login.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/logout.xml b/app/src/main/res/drawable/logout.xml new file mode 100644 index 0000000..a62d2ab --- /dev/null +++ b/app/src/main/res/drawable/logout.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/manager_login.xml b/app/src/main/res/drawable/manager_login.xml new file mode 100644 index 0000000..0f60d2a --- /dev/null +++ b/app/src/main/res/drawable/manager_login.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/membership1.xml b/app/src/main/res/drawable/membership1.xml new file mode 100644 index 0000000..d0127ea --- /dev/null +++ b/app/src/main/res/drawable/membership1.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/membership2.xml b/app/src/main/res/drawable/membership2.xml new file mode 100644 index 0000000..c8a6afd --- /dev/null +++ b/app/src/main/res/drawable/membership2.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/membership3.xml b/app/src/main/res/drawable/membership3.xml new file mode 100644 index 0000000..93ab234 --- /dev/null +++ b/app/src/main/res/drawable/membership3.xml @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/menu_button.xml b/app/src/main/res/drawable/menu_button.xml new file mode 100644 index 0000000..63dcc21 --- /dev/null +++ b/app/src/main/res/drawable/menu_button.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/newbody_logo_background.xml b/app/src/main/res/drawable/newbody_logo_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/app/src/main/res/drawable/newbody_logo_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/next.xml b/app/src/main/res/drawable/next.xml new file mode 100644 index 0000000..8355dad --- /dev/null +++ b/app/src/main/res/drawable/next.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/next_button.xml b/app/src/main/res/drawable/next_button.xml new file mode 100644 index 0000000..0f8a6c2 --- /dev/null +++ b/app/src/main/res/drawable/next_button.xml @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/notice.png b/app/src/main/res/drawable/notice.png new file mode 100644 index 0000000..1d1aaef Binary files /dev/null and b/app/src/main/res/drawable/notice.png differ diff --git a/app/src/main/res/drawable/pose_fix.jpg b/app/src/main/res/drawable/pose_fix.jpg new file mode 100644 index 0000000..1d2e6ac Binary files /dev/null and b/app/src/main/res/drawable/pose_fix.jpg differ diff --git a/app/src/main/res/drawable/pose_ranking.jpg b/app/src/main/res/drawable/pose_ranking.jpg new file mode 100644 index 0000000..e2f883a Binary files /dev/null and b/app/src/main/res/drawable/pose_ranking.jpg differ diff --git a/app/src/main/res/drawable/premium.png b/app/src/main/res/drawable/premium.png new file mode 100644 index 0000000..e298be0 Binary files /dev/null and b/app/src/main/res/drawable/premium.png differ diff --git a/app/src/main/res/drawable/premium_badge.png b/app/src/main/res/drawable/premium_badge.png new file mode 100644 index 0000000..8ec6f06 Binary files /dev/null and b/app/src/main/res/drawable/premium_badge.png differ diff --git a/app/src/main/res/drawable/premium_benefit.png b/app/src/main/res/drawable/premium_benefit.png new file mode 100644 index 0000000..226442b Binary files /dev/null and b/app/src/main/res/drawable/premium_benefit.png differ diff --git a/app/src/main/res/drawable/prevbutton.xml b/app/src/main/res/drawable/prevbutton.xml new file mode 100644 index 0000000..0b83244 --- /dev/null +++ b/app/src/main/res/drawable/prevbutton.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/profile_man.xml b/app/src/main/res/drawable/profile_man.xml new file mode 100644 index 0000000..38c2fdd --- /dev/null +++ b/app/src/main/res/drawable/profile_man.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progressbar_1.xml b/app/src/main/res/drawable/progressbar_1.xml new file mode 100644 index 0000000..cbff18f --- /dev/null +++ b/app/src/main/res/drawable/progressbar_1.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/protection.xml b/app/src/main/res/drawable/protection.xml new file mode 100644 index 0000000..a3c640e --- /dev/null +++ b/app/src/main/res/drawable/protection.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/push_alarm.xml b/app/src/main/res/drawable/push_alarm.xml new file mode 100644 index 0000000..6e97ddd --- /dev/null +++ b/app/src/main/res/drawable/push_alarm.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/pushup.png b/app/src/main/res/drawable/pushup.png new file mode 100644 index 0000000..9b39e4d Binary files /dev/null and b/app/src/main/res/drawable/pushup.png differ diff --git a/app/src/main/res/drawable/ranking.png b/app/src/main/res/drawable/ranking.png new file mode 100644 index 0000000..7bb04d0 Binary files /dev/null and b/app/src/main/res/drawable/ranking.png differ diff --git a/app/src/main/res/drawable/record.png b/app/src/main/res/drawable/record.png new file mode 100644 index 0000000..f6140a4 Binary files /dev/null and b/app/src/main/res/drawable/record.png differ diff --git a/app/src/main/res/drawable/record_count.jpg b/app/src/main/res/drawable/record_count.jpg new file mode 100644 index 0000000..59c0e70 Binary files /dev/null and b/app/src/main/res/drawable/record_count.jpg differ diff --git a/app/src/main/res/drawable/red_background.xml b/app/src/main/res/drawable/red_background.xml new file mode 100644 index 0000000..65ea747 --- /dev/null +++ b/app/src/main/res/drawable/red_background.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_button.xml b/app/src/main/res/drawable/round_button.xml new file mode 100644 index 0000000..05335d7 --- /dev/null +++ b/app/src/main/res/drawable/round_button.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/drawable/rounded_corners.xml b/app/src/main/res/drawable/rounded_corners.xml new file mode 100644 index 0000000..f3a3f27 --- /dev/null +++ b/app/src/main/res/drawable/rounded_corners.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable/side.png b/app/src/main/res/drawable/side.png new file mode 100644 index 0000000..ecb2e45 Binary files /dev/null and b/app/src/main/res/drawable/side.png differ diff --git a/app/src/main/res/drawable/squat.png b/app/src/main/res/drawable/squat.png new file mode 100644 index 0000000..80db93e Binary files /dev/null and b/app/src/main/res/drawable/squat.png differ diff --git a/app/src/main/res/drawable/trainerpic.png b/app/src/main/res/drawable/trainerpic.png new file mode 100644 index 0000000..c5d8bec Binary files /dev/null and b/app/src/main/res/drawable/trainerpic.png differ diff --git a/app/src/main/res/drawable/triceps.png b/app/src/main/res/drawable/triceps.png new file mode 100644 index 0000000..f8491be Binary files /dev/null and b/app/src/main/res/drawable/triceps.png differ diff --git a/app/src/main/res/drawable/video.png b/app/src/main/res/drawable/video.png new file mode 100644 index 0000000..4616417 Binary files /dev/null and b/app/src/main/res/drawable/video.png differ diff --git a/app/src/main/res/drawable/walk.gif b/app/src/main/res/drawable/walk.gif new file mode 100644 index 0000000..5807167 Binary files /dev/null and b/app/src/main/res/drawable/walk.gif differ diff --git a/app/src/main/res/drawable/warmup.png b/app/src/main/res/drawable/warmup.png new file mode 100644 index 0000000..9cbf30c Binary files /dev/null and b/app/src/main/res/drawable/warmup.png differ diff --git a/app/src/main/res/drawable/water_glass.xml b/app/src/main/res/drawable/water_glass.xml new file mode 100644 index 0000000..577f7d5 --- /dev/null +++ b/app/src/main/res/drawable/water_glass.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/welcome_scr.xml b/app/src/main/res/drawable/welcome_scr.xml new file mode 100644 index 0000000..c6c5daf --- /dev/null +++ b/app/src/main/res/drawable/welcome_scr.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/welcome_scr1.xml b/app/src/main/res/drawable/welcome_scr1.xml new file mode 100644 index 0000000..0f8ce6c --- /dev/null +++ b/app/src/main/res/drawable/welcome_scr1.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/welcome_scr2.xml b/app/src/main/res/drawable/welcome_scr2.xml new file mode 100644 index 0000000..95989ae --- /dev/null +++ b/app/src/main/res/drawable/welcome_scr2.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/welcome_scr3.xml b/app/src/main/res/drawable/welcome_scr3.xml new file mode 100644 index 0000000..c64b043 --- /dev/null +++ b/app/src/main/res/drawable/welcome_scr3.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/welcome_scr4.xml b/app/src/main/res/drawable/welcome_scr4.xml new file mode 100644 index 0000000..2c6e94c --- /dev/null +++ b/app/src/main/res/drawable/welcome_scr4.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/yoga.png b/app/src/main/res/drawable/yoga.png new file mode 100644 index 0000000..41fde22 Binary files /dev/null and b/app/src/main/res/drawable/yoga.png differ diff --git a/app/src/main/res/drawable/yoga_lock.png b/app/src/main/res/drawable/yoga_lock.png new file mode 100644 index 0000000..fb88580 Binary files /dev/null and b/app/src/main/res/drawable/yoga_lock.png differ diff --git a/app/src/main/res/layout/acticity_posture.xml b/app/src/main/res/layout/acticity_posture.xml new file mode 100644 index 0000000..6fb259f --- /dev/null +++ b/app/src/main/res/layout/acticity_posture.xml @@ -0,0 +1,649 @@ + + + + + + +