Skip to content

adapt for play store#105

Open
zfdang wants to merge 7 commits into
masterfrom
refactor
Open

adapt for play store#105
zfdang wants to merge 7 commits into
masterfrom
refactor

Conversation

@zfdang
Copy link
Copy Markdown
Owner

@zfdang zfdang commented Mar 20, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Privacy policy link is now directly accessible from the About section
    • Accessibility permission request displays a confirmation dialog before opening system settings
  • Improvements

    • Enhanced event handling performance with intelligent debouncing optimization
    • Updated core dependencies and build infrastructure to latest stable versions
    • Added Android App Bundle distribution format support

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, 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!

This pull request focuses on adapting the application for Play Store submission by addressing key requirements related to user privacy and accessibility service usage. It introduces a clear disclosure for the AccessibilityService API, adds a privacy policy link, and includes a throttling mechanism for accessibility events to improve performance and stability.

Highlights

  • Accessibility Service Disclosure: Introduced a prominent disclosure dialog for AccessibilityService API usage, explaining its purpose and data handling, before directing users to system settings.
  • Event Throttling: Implemented a throttling mechanism for content changed events within the AccessibilityService to prevent rapid processing and improve stability.
  • Privacy Policy Integration: Added a dedicated section in the 'About' screen to display a privacy policy link, along with its corresponding string resource.
  • Build Configuration Update: Modified gradle.properties to include a flag for suppressing unsupported compile SDK warnings, likely to ensure compatibility for Play Store submission.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adapts the application for the Google Play Store by adding a prominent disclosure for the Accessibility Service usage and a link to the privacy policy. It also introduces a throttling mechanism for CONTENT_CHANGED events to improve performance. My review includes a critical fix for gradle.properties where a newline is missing, a suggestion to extract hardcoded strings to resources for better maintainability and internationalization, and a recommendation to replace a magic number with a constant.

Comment thread gradle.properties Outdated
KEYSTORE_PASSWORD=touchhelper
KEY_ALIAS=touchhelper
KEY_PASSWORD=touchhelper No newline at end of file
KEY_PASSWORD=touchhelperandroid.suppressUnsupportedCompileSdk=35
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

It seems like a new property android.suppressUnsupportedCompileSdk=35 was appended to the KEY_PASSWORD line without a newline. This is incorrect and will likely cause build failures or unexpected behavior. Please add a newline before android.suppressUnsupportedCompileSdk=35.

KEY_PASSWORD=touchhelper
android.suppressUnsupportedCompileSdk=35

}

long currentTime = System.currentTimeMillis();
if (currentTime - lastContentChangedTime < 150) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The value 150 is a magic number. It's better to define it as a named constant to improve readability and maintainability, for example: private static final int CONTENT_CHANGED_THROTTLE_INTERVAL_MS = 150; at the class level.

Comment on lines +85 to +94
new androidx.appcompat.app.AlertDialog.Builder(getContext())
.setTitle("重要说明 (Prominent Disclosure)")
.setMessage("本应用需要使用无障碍服务(AccessibilityService API)来帮您在其他应用中自动查找并点击屏幕上的指定控件(例如各类重复性的按钮)。\n\n本应用属于自动化工具,所有的点击操作均基于您的配置和触发策略。\n本应用完全离线运行,不会收集、存储、传输或分享您的任何个人数据及敏感信息。\n\n请点击“同意”以继续前往系统设置中授权此服务。")
.setPositiveButton("同意", (dialog, which) -> {
Intent intent_abs = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent_abs.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent_abs);
})
.setNegativeButton("拒绝", null)
.show();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The title, message, and button texts for this AlertDialog are hardcoded. It's a best practice to extract these strings into strings.xml resources. This improves maintainability and makes it easier to support multiple languages in the future.

zfdang and others added 6 commits March 20, 2026 08:25
R8 was obfuscating Navigator subclasses, breaking @Navigator.Name
annotation lookup at runtime and causing crash on app launch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update AGP 8.2.2 → 8.7.3, Gradle 8.4 → 8.9
- Update all androidx dependencies to latest stable versions
- Replace deprecated lifecycle-extensions with lifecycle-viewmodel+livedata
- Replace deprecated ViewModelProviders with ViewModelProvider
- Update gson 2.8.5 → 2.11.0, test dependencies to latest
- Add AAB (App Bundle) build to CI workflow for Play Store submission
- Disable jetifier (no longer needed with modern deps)
- Remove unused fileTree dependency
- Only publish releases on master branch, other branches build only
- Fix privacy policy URL to point to existing docs/privacy.html
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 18, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 59da02d8-ad36-402a-9271-97400d465c04

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
app/src/main/java/com/zfdang/touchhelper/ui/home/HomeFragment.java (1)

85-94: Good Play Store compliance dialog; consider using requireContext().

The prominent disclosure dialog for accessibility services meets Play Store requirements. However, getContext() can return null in edge cases (fragment not attached). Consider using requireContext() which throws a clear IllegalStateException if the fragment is not attached, rather than risking an NPE.

Suggested improvement
-                new androidx.appcompat.app.AlertDialog.Builder(getContext())
+                new androidx.appcompat.app.AlertDialog.Builder(requireContext())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/zfdang/touchhelper/ui/home/HomeFragment.java` around
lines 85 - 94, In HomeFragment replace the nullable getContext() call used in
the AlertDialog.Builder with requireContext() to avoid a possible null context
when the fragment is not attached; update the builder invocation (the new
androidx.appcompat.app.AlertDialog.Builder(...) call) to use requireContext()
and ensure the intent launch remains valid (e.g., keep the Intent creation and
flags in the setPositiveButton callback, optionally using requireActivity() if
you prefer an activity context for startActivity).
.github/workflows/build_apk.yml (1)

50-57: Consider narrowing the APK artifact path.

The APK artifact path ./app/build/outputs/apk/ includes both debug and release subdirectories, while the AAB path is scoped to bundle/release/. For consistency and to avoid uploading unintended files, consider narrowing to release only.

Suggested fix
     - name: Upload APK to artifacts
       uses: actions/upload-artifact@v4
       with:
         name: TouchHelper-APK
-        path: ./app/build/outputs/apk/
+        path: ./app/build/outputs/apk/release/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build_apk.yml around lines 50 - 57, The APK artifact
currently uploads the entire ./app/build/outputs/apk/ (which includes debug and
release); update the TouchHelper-APK artifact configuration to narrow the path
to the release APKs only (e.g., change the path used by the artifact named
"TouchHelper-APK" to the release folder such as ./app/build/outputs/apk/release/
or a glob that selects only release APK files) so only release artifacts are
uploaded, matching the AAB scoping.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/zfdang/touchhelper/TouchHelperServiceImpl.java`:
- Around line 365-370: The debounce uses wall-clock time via
System.currentTimeMillis(), which can jump; replace that call with a monotonic
clock (SystemClock.elapsedRealtime()) for computing the delta against
lastContentChangedTime in TouchHelperServiceImpl (the variable
lastContentChangedTime and the block that sets it). Update the reference so
lastContentChangedTime stores elapsedRealtime() values and ensure
android.os.SystemClock is imported; keep the comparison logic the same (compare
elapsedRealtime() - lastContentChangedTime < 150) and then set
lastContentChangedTime = SystemClock.elapsedRealtime().

In `@app/src/main/res/layout/fragment_about.xml`:
- Around line 75-76: Replace the legacy RTL-unsafe attributes
android:paddingLeft and android:paddingRight in the fragment_about layout with
directional attributes android:paddingStart and android:paddingEnd (remove the
left/right attributes) so the layout is RTL-safe; update the attributes where
they appear in fragment_about.xml (lines showing android:paddingLeft and
android:paddingRight) to android:paddingStart and android:paddingEnd
respectively, leveraging the project's minSdkVersion >= 26 which supports
directional padding.
- Around line 68-81: The fragment can overflow on small screens because the
stacked TextViews (e.g., `@id/textView_weblink` and `@id/textView_privacy`) live
directly in the non-scrollable ConstraintLayout; wrap the scrollable portion in
a NestedScrollView: create a NestedScrollView (or ScrollView) inside the root
ConstraintLayout, move the TextViews that should scroll (weblink, privacy, any
other descriptive TextViews) into a single vertical container (LinearLayout or
ConstraintLayout) inside that NestedScrollView, set those child views to
wrap_content height, and constrain the NestedScrollView between the top of the
parent and the top of the bottom copyright view (use
app:layout_constraintBottom_toTopOf="@id/textView_copyright"); preserve the
existing IDs and link attributes (autoLink, linksClickable) and ensure the
NestedScrollView width is match_parent so long text can wrap and scroll instead
of being clipped.

---

Nitpick comments:
In @.github/workflows/build_apk.yml:
- Around line 50-57: The APK artifact currently uploads the entire
./app/build/outputs/apk/ (which includes debug and release); update the
TouchHelper-APK artifact configuration to narrow the path to the release APKs
only (e.g., change the path used by the artifact named "TouchHelper-APK" to the
release folder such as ./app/build/outputs/apk/release/ or a glob that selects
only release APK files) so only release artifacts are uploaded, matching the AAB
scoping.

In `@app/src/main/java/com/zfdang/touchhelper/ui/home/HomeFragment.java`:
- Around line 85-94: In HomeFragment replace the nullable getContext() call used
in the AlertDialog.Builder with requireContext() to avoid a possible null
context when the fragment is not attached; update the builder invocation (the
new androidx.appcompat.app.AlertDialog.Builder(...) call) to use
requireContext() and ensure the intent launch remains valid (e.g., keep the
Intent creation and flags in the setPositiveButton callback, optionally using
requireActivity() if you prefer an activity context for startActivity).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b2707999-69da-440a-b628-3d47d032d497

📥 Commits

Reviewing files that changed from the base of the PR and between 037d2c0 and 4d0beff.

📒 Files selected for processing (10)
  • .github/workflows/build_apk.yml
  • app/build.gradle
  • app/src/main/java/com/zfdang/touchhelper/TouchHelperServiceImpl.java
  • app/src/main/java/com/zfdang/touchhelper/ui/about/AboutFragment.java
  • app/src/main/java/com/zfdang/touchhelper/ui/home/HomeFragment.java
  • app/src/main/res/layout/fragment_about.xml
  • app/src/main/res/values/strings.xml
  • build.gradle
  • gradle.properties
  • gradle/wrapper/gradle-wrapper.properties
💤 Files with no reviewable changes (1)
  • app/src/main/java/com/zfdang/touchhelper/ui/about/AboutFragment.java

Comment on lines +365 to +370
long currentTime = System.currentTimeMillis();
if (currentTime - lastContentChangedTime < 150) {
break;
}
lastContentChangedTime = currentTime;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify timer APIs used for debounce/interval checks in the repo.
# Expectation: elapsedRealtime()/uptimeMillis() for elapsed checks, avoid currentTimeMillis() for throttling.
rg -n -C2 'currentTimeMillis\(|elapsedRealtime\(|uptimeMillis\('

Repository: zfdang/Android-Touch-Helper

Length of output: 626


🏁 Script executed:

# Read the full context around line 365 and nearby code
sed -n '350,380p' app/src/main/java/com/zfdang/touchhelper/TouchHelperServiceImpl.java

Repository: zfdang/Android-Touch-Helper

Length of output: 1549


🏁 Script executed:

# Find where lastContentChangedTime is declared and initialized
rg -n 'lastContentChangedTime' app/src/main/java/com/zfdang/touchhelper/TouchHelperServiceImpl.java

Repository: zfdang/Android-Touch-Helper

Length of output: 254


🏁 Script executed:

# Check current imports in the file
head -30 app/src/main/java/com/zfdang/touchhelper/TouchHelperServiceImpl.java

Repository: zfdang/Android-Touch-Helper

Length of output: 1155


Use a monotonic clock for debounce timing.

Line 365 uses System.currentTimeMillis(), which returns wall-clock time that can jump due to system clock adjustments (NTP sync, manual adjustments, etc.), breaking debounce logic. Use SystemClock.elapsedRealtime() for elapsed interval measurements.

Proposed fix
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemClock;
@@
-                    long currentTime = System.currentTimeMillis();
+                    long currentTime = SystemClock.elapsedRealtime();
                     if (currentTime - lastContentChangedTime < 150) {
                         break;
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
long currentTime = System.currentTimeMillis();
if (currentTime - lastContentChangedTime < 150) {
break;
}
lastContentChangedTime = currentTime;
long currentTime = SystemClock.elapsedRealtime();
if (currentTime - lastContentChangedTime < 150) {
break;
}
lastContentChangedTime = currentTime;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/zfdang/touchhelper/TouchHelperServiceImpl.java` around
lines 365 - 370, The debounce uses wall-clock time via
System.currentTimeMillis(), which can jump; replace that call with a monotonic
clock (SystemClock.elapsedRealtime()) for computing the delta against
lastContentChangedTime in TouchHelperServiceImpl (the variable
lastContentChangedTime and the block that sets it). Update the reference so
lastContentChangedTime stores elapsedRealtime() values and ensure
android.os.SystemClock is imported; keep the comparison logic the same (compare
elapsedRealtime() - lastContentChangedTime < 150) and then set
lastContentChangedTime = SystemClock.elapsedRealtime().

Comment on lines +68 to +81
<TextView
android:id="@+id/textView_privacy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:autoLink="web"
android:linksClickable="true"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:text="@string/about_privacy"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView_weblink" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1) Confirm this layout is not already wrapped by a scroll container via include/inflate usage context.
rg -n -C3 'fragment_about|R\.layout\.fragment_about|inflate\([^)]*fragment_about'

# 2) List long text blocks in this layout that increase vertical pressure.
rg -n --type=xml -C1 'textView_app_introduction|textView_weblink|textView_privacy|layout_constraintBottom_toBottomOf'

Repository: zfdang/Android-Touch-Helper

Length of output: 5080


🏁 Script executed:

cat -n app/src/main/res/layout/fragment_about.xml

Repository: zfdang/Android-Touch-Helper

Length of output: 4438


🏁 Script executed:

rg -n -B5 -A5 'FragmentContainerView|fragment_container|R\.id\..*container' app/src/main/res/layout/activity_main.xml

Repository: zfdang/Android-Touch-Helper

Length of output: 53


🏁 Script executed:

cat -n app/src/main/res/layout/activity_main.xml

Repository: zfdang/Android-Touch-Helper

Length of output: 1788


Wrap content in ScrollView or NestedScrollView to prevent overflow.

The fragment's root ConstraintLayout (and parent NavHostFragment) are non-scrollable. Multiple stacked TextViews with match_parent width—especially weblink and privacy fields with wrappable URLs—can overflow on small screens or with large font sizes, causing content clipping below the bottom-anchored copyright text. Consider wrapping the content above the copyright view in a NestedScrollView to ensure all text remains accessible.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/layout/fragment_about.xml` around lines 68 - 81, The
fragment can overflow on small screens because the stacked TextViews (e.g.,
`@id/textView_weblink` and `@id/textView_privacy`) live directly in the
non-scrollable ConstraintLayout; wrap the scrollable portion in a
NestedScrollView: create a NestedScrollView (or ScrollView) inside the root
ConstraintLayout, move the TextViews that should scroll (weblink, privacy, any
other descriptive TextViews) into a single vertical container (LinearLayout or
ConstraintLayout) inside that NestedScrollView, set those child views to
wrap_content height, and constrain the NestedScrollView between the top of the
parent and the top of the bottom copyright view (use
app:layout_constraintBottom_toTopOf="@id/textView_copyright"); preserve the
existing IDs and link attributes (autoLink, linksClickable) and ensure the
NestedScrollView width is match_parent so long text can wrap and scroll instead
of being clipped.

Comment on lines +75 to +76
android:paddingLeft="12dp"
android:paddingRight="12dp"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all directional-padding opportunities in XML layouts.
rg -n --type=xml -C2 'paddingLeft|paddingRight'

Repository: zfdang/Android-Touch-Helper

Length of output: 2830


🏁 Script executed:

# Check the project's minSdkVersion
find . -name "AndroidManifest.xml" -o -name "build.gradle" -o -name "build.gradle.kts" | head -5

Repository: zfdang/Android-Touch-Helper

Length of output: 139


🏁 Script executed:

# Also check for minSdkVersion in gradle files
rg -n "minSdkVersion" --type=gradle

Repository: zfdang/Android-Touch-Helper

Length of output: 115


Use directional padding attributes for RTL-safe layouts.

Lines 75-76 should use android:paddingStart and android:paddingEnd instead of paddingLeft and paddingRight. The project's minSdkVersion is 26, which fully supports directional padding (available since API 17).

♻️ Proposed update
-        android:paddingLeft="12dp"
-        android:paddingRight="12dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/layout/fragment_about.xml` around lines 75 - 76, Replace the
legacy RTL-unsafe attributes android:paddingLeft and android:paddingRight in the
fragment_about layout with directional attributes android:paddingStart and
android:paddingEnd (remove the left/right attributes) so the layout is RTL-safe;
update the attributes where they appear in fragment_about.xml (lines showing
android:paddingLeft and android:paddingRight) to android:paddingStart and
android:paddingEnd respectively, leveraging the project's minSdkVersion >= 26
which supports directional padding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant