-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/android block #230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feat/android block #230
Conversation
- FocusAccessibilityService를 추가하여 미허용 앱 탐지 및 차단 - 차단 상태를 제어하기 위해 MainActivity에 MethodChannel 구현 - 올바른 메인액티비티 패키지 구조(com.example -> com.company) - 매니페스트에 접근성 서비스 구성 및 권한 추가
- Android 네이티브 서비스와 통신하기 위해 NativeBlockController 추가 - 접근성 서비스에 대한 권한 안내 팝업 구현 - DeepTimeScreen의 잠금 아이콘 탭에서 차단 로직 시작/정지 트리거
Summary of ChangesHello @thdudgus, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 Pull Request는 Android 기기에서 사용자가 독서에 집중할 수 있도록 방해되는 다른 애플리케이션의 실행을 차단하는 포커스 모드 기능을 도입합니다. 이를 위해 Android의 접근성 서비스를 활용하여 앱 전환 이벤트를 감지하고, Flutter와 Native 코드 간의 통신 채널을 통해 포커스 모드의 활성화/비활성화 및 필요한 접근성 권한 관리를 수행합니다. 사용자 경험을 고려하여 권한이 없을 경우 설정 페이지로 안내하는 기능도 포함되어 있습니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
이번 PR은 접근성 서비스를 사용하여 안드로이드에서 집중 모드를 위한 앱 차단 기능을 구현한 것이네요. 서비스와 메소드 채널 통신을 위한 네이티브 안드로이드 코드와 플러터 프론트엔드가 잘 구조화되어 있습니다. 리뷰 결과, 성능, 보안, 코드 유지보수성 측면에서 몇 가지 개선점을 발견했습니다. 구체적으로 SharedPreferences 인스턴스 캐싱, 불필요한 권한 제거, 하드코딩된 값과 문자열 중복 방지, 일부 Dart 코드 정리 등을 제안했습니다. 전반적으로 이 복잡한 기능을 잘 구현하셨습니다.
| android:accessibilityEventTypes="typeWindowStateChanged" | ||
| android:accessibilityFeedbackType="feedbackGeneric" | ||
| android:notificationTimeout="100" | ||
| android:canRetrieveWindowContent="true" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| val packageName = event.packageName?.toString() ?: return | ||
|
|
||
| // Check if blocking is enabled from SharedPrefs | ||
| val prefs: SharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Log.d(TAG, "Blocking package: $packageName") | ||
|
|
||
| // Action: Bring our app to front to make it clear why | ||
| val intent = packageManager.getLaunchIntentForPackage("com.company.bookstar") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
패키지 이름 "com.company.bookstar"가 하드코딩되어 있습니다. applicationContext.packageName을 사용하면 패키지 이름이 변경될 경우 발생할 수 있는 문제를 피하고 코드를 더 견고하게 만들 수 있습니다.
| val intent = packageManager.getLaunchIntentForPackage("com.company.bookstar") | |
| val intent = packageManager.getLaunchIntentForPackage(applicationContext.packageName) |
|
|
||
| class MainActivity : FlutterActivity() { | ||
| // Channel name as requested | ||
| private val CHANNEL = "com.example.blocker/control" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
채널 이름에 com.example이 사용되었습니다. 채널 이름의 접두사로 앱의 패키지 이름을 사용하는 것이 고유성을 보장하는 좋은 방법입니다. 이렇게 하면 다른 플러그인이나 앱과의 잠재적인 충돌을 피할 수 있습니다. lib/core/native_block_controller.dart 파일에서도 함께 수정해야 합니다.
| private val CHANNEL = "com.example.blocker/control" | |
| private val CHANNEL = "com.company.bookstar/blocker/control" |
| val prefs = getSharedPreferences("FocusModePrefs", Context.MODE_PRIVATE) | ||
| prefs.edit().putBoolean("is_active", true).apply() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| import 'package:flutter/services.dart'; | ||
|
|
||
| class NativeBlockController { | ||
| static const MethodChannel _channel = MethodChannel('com.example.blocker/control'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Future<void> startBlocking() async { | ||
| try { | ||
| await _channel.invokeMethod('startBlock'); | ||
| print('Blocking started on native side.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| onTap: () async { | ||
| if (!_isPermissionGranted) { | ||
| // Show dialog to guide user before requesting permission | ||
| final bool shouldGoToSettings = await _showPermissionGuideDialog(); | ||
|
|
||
| if (shouldGoToSettings) { | ||
| final bool settingsOpened = await _blockController.requestPermission(); | ||
| if (settingsOpened) { | ||
| // Wait for user to possibly enable it and come back | ||
| // Note: We can't know exactly when they come back, but lifecycle listener handles re-check | ||
| } | ||
| } | ||
| // Don't proceed to toggle lock if permission wasn't granted yet | ||
| return; | ||
| } | ||
|
|
||
| // If permission is granted, proceed with blocking/unblocking logic | ||
| if (!widget.isLock) { // If currently unlocked (false), tapping means locking (true) | ||
| await _blockController.startBlocking(); | ||
| } else { // If currently locked (true), tapping means unlocking (false) | ||
| await _blockController.stopBlocking(); | ||
| } | ||
| widget.onLockToggle(); // Call original toggle callback to update widget.isLock | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feat # 226
변경사항
앱 차단 기능으로 포커스 모드 구현
스크린샷

After
해당 팝업을 통해 접근성 설정 페이지 (기기 시스템 설정)로 이동 -> 허용 후엔 북스타 외 다른 앱 차단 기능 활성화