<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Phone Operator Team</title>
    <description>The latest articles on DEV Community by Phone Operator Team (@phoneoperatorapp).</description>
    <link>https://dev.to/phoneoperatorapp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4060469%2F04d6711f-6983-43ae-96f4-039f5f9fdf4d.png</url>
      <title>DEV Community: Phone Operator Team</title>
      <link>https://dev.to/phoneoperatorapp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/phoneoperatorapp"/>
    <language>en</language>
    <item>
      <title>Building an on-device AI journal that does not confuse the prompt with the user's voice</title>
      <dc:creator>Phone Operator Team</dc:creator>
      <pubDate>Mon, 03 Aug 2026 15:59:12 +0000</pubDate>
      <link>https://dev.to/phoneoperatorapp/building-an-on-device-ai-journal-that-does-not-confuse-the-prompt-with-the-users-voice-3pf9</link>
      <guid>https://dev.to/phoneoperatorapp/building-an-on-device-ai-journal-that-does-not-confuse-the-prompt-with-the-users-voice-3pf9</guid>
      <description>&lt;p&gt;A journaling assistant has a deceptively hard job: it must respond to a person's meaning, not simply react to emotional keywords.&lt;/p&gt;

&lt;p&gt;While building &lt;strong&gt;Rixin Mind Journal&lt;/strong&gt;, a private Android journal with on-device AI, I learned that a small local model can sound fluent while still making a basic semantic mistake: treating the system's daily question as if the user had asked it.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;System prompt: "When did you feel most peaceful today?"&lt;br&gt;&lt;br&gt;
User answer: "After everyone went to sleep, I worked alone."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A shallow pipeline may focus on "worked alone" and immediately warn about overwork. A better response first notices what solitude provided: uninterrupted attention, autonomy, relief from social pressure, or simply a quiet room.&lt;/p&gt;

&lt;p&gt;That distinction changed the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Keep the system prompt and user answer in separate fields
&lt;/h2&gt;

&lt;p&gt;Do not concatenate everything into an undifferentiated paragraph and hope the model infers the roles.&lt;/p&gt;

&lt;p&gt;The analysis input explicitly labels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Question asked by the app&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Answer written by the user&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optional free-form diary text&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prior patterns&lt;/strong&gt;, when generating a weekly or monthly report&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The instruction also states that the question is context, not a claim or request made by the user.&lt;/p&gt;

&lt;p&gt;This sounds obvious, but it eliminated an entire class of confidently wrong responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Analyze the whole entry before generating prose
&lt;/h2&gt;

&lt;p&gt;Keyword matching is useful as a safety net, but it is not understanding.&lt;/p&gt;

&lt;p&gt;"Lazy" can mean shame, fatigue, avoidance, rebellion, depression, humor, or a temporary loss of routine. "Fine" can mean genuine calm or emotional shutdown. "Alone" can mean loneliness or freedom.&lt;/p&gt;

&lt;p&gt;The pipeline therefore separates analysis from writing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the concrete situation.&lt;/li&gt;
&lt;li&gt;Estimate emotional valence and intensity.&lt;/li&gt;
&lt;li&gt;Look for mixed emotions and negation.&lt;/li&gt;
&lt;li&gt;Infer the likely need or tension.&lt;/li&gt;
&lt;li&gt;Select one relevant psychological frame.&lt;/li&gt;
&lt;li&gt;Generate one small, behaviorally specific next step.&lt;/li&gt;
&lt;li&gt;Write the final response in a warm voice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final prose is not allowed to expose the internal labels or repeat large pieces of the diary.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Receive emotion before offering advice
&lt;/h2&gt;

&lt;p&gt;Advice given too early feels like correction.&lt;/p&gt;

&lt;p&gt;The response order is deliberately constrained:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Recognition:&lt;/strong&gt; show that the experience was understood.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Insight:&lt;/strong&gt; name one useful pattern, conflict, or need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; suggest one small step that could survive an ordinary day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closing line:&lt;/strong&gt; end with warmth, not another question the user cannot answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This matters for positive emotion too. A reflection engine should not treat every joyful entry as hidden pathology. Relief, pride, affection, playfulness, gratitude, and calm are information about what supports the person.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Use expert rules as guardrails, not as the final writer
&lt;/h2&gt;

&lt;p&gt;Early versions relied too heavily on templates. They were safe, but different diary entries produced suspiciously similar responses.&lt;/p&gt;

&lt;p&gt;The current approach uses expert rules to control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;role separation&lt;/li&gt;
&lt;li&gt;emotion-negation checks&lt;/li&gt;
&lt;li&gt;crisis language&lt;/li&gt;
&lt;li&gt;medical boundaries&lt;/li&gt;
&lt;li&gt;response order&lt;/li&gt;
&lt;li&gt;repetition limits&lt;/li&gt;
&lt;li&gt;banned meta phrases such as "the user answered..."&lt;/li&gt;
&lt;li&gt;action specificity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The local model is still responsible for most of the wording. Rules shape the lane; they do not write every sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Evaluate semantic fit, not only grammatical quality
&lt;/h2&gt;

&lt;p&gt;A fluent answer can still be useless.&lt;/p&gt;

&lt;p&gt;Our test cases cover different ages, jobs, relationships and emotional states. Each output is reviewed against questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did it identify the actual situation?&lt;/li&gt;
&lt;li&gt;Did it preserve positive emotion instead of turning it negative?&lt;/li&gt;
&lt;li&gt;Did it acknowledge mixed feelings?&lt;/li&gt;
&lt;li&gt;Is the advice concrete enough to attempt?&lt;/li&gt;
&lt;li&gt;Could the same response be pasted under a different diary entry?&lt;/li&gt;
&lt;li&gt;Does it sound like a person, or like a classification report?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most valuable failure metric is &lt;strong&gt;replaceability&lt;/strong&gt;. If an insight could fit twenty unrelated entries, it is too generic.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Privacy is part of the product behavior
&lt;/h2&gt;

&lt;p&gt;On-device processing is not only an infrastructure decision. It changes what users are willing to write.&lt;/p&gt;

&lt;p&gt;Rixin keeps diary writing local-first and performs AI reflection on the device. It supports guided questions, free-form journaling, daily insights, and longer weekly/monthly letters. The app is for self-reflection, not diagnosis or therapy.&lt;/p&gt;

&lt;p&gt;The tradeoff is real: a small local model has less raw capability than a large cloud model. The way forward is not to pretend otherwise, but to narrow the task, provide expert structure, test diverse failure cases, and make the output earn its place.&lt;/p&gt;

&lt;p&gt;If you are building any AI product that handles personal writing, I would recommend testing role confusion, negation, mixed emotion, positive emotion, and generic-response reuse before polishing the UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rixin Mind Journal on Google Play:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.rixin.app" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.rixin.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would especially value feedback from Android and local-AI developers on the balance between privacy, model size, and semantic accuracy.&lt;/p&gt;

</description>
      <category>privacy</category>
    </item>
    <item>
      <title>Designing Reliable No-Root Android Tap and Swipe Automation</title>
      <dc:creator>Phone Operator Team</dc:creator>
      <pubDate>Mon, 03 Aug 2026 11:19:59 +0000</pubDate>
      <link>https://dev.to/phoneoperatorapp/designing-reliable-no-root-android-tap-and-swipe-automation-1bdn</link>
      <guid>https://dev.to/phoneoperatorapp/designing-reliable-no-root-android-tap-and-swipe-automation-1bdn</guid>
      <description>&lt;p&gt;Repeated taps look simple until you try to automate them reliably across real Android devices. A gesture that works in a test screen can miss its target inside another app, drift after rotation, stop when the display sleeps, or become impossible to cancel when an overlay loses state.&lt;/p&gt;

&lt;p&gt;I am building &lt;strong&gt;Phone Operator&lt;/strong&gt;, a no-root Android automation utility, and these are the design rules that made the biggest difference. The goal here is not to automate purchases, CAPTCHA solving, fake engagement, or game-rule bypasses. It is to make user-configured, local gesture sequences predictable for repetitive personal workflows and testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Separate the control plane from the execution plane
&lt;/h2&gt;

&lt;p&gt;A robust automation app has two different jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;control plane&lt;/strong&gt; lets a user create actions, change intervals, move markers, save scripts, and start or pause a run.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;execution plane&lt;/strong&gt; validates the script, resolves coordinates, dispatches gestures, tracks cancellation, and reports progress.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mixing both jobs inside an overlay service creates subtle failures. Dragging the floating menu can mutate gesture state. Rebuilding the overlay can cancel a scheduled action. A configuration edit can race with the currently executing action.&lt;/p&gt;

&lt;p&gt;A safer model is to compile the editable script into an immutable runtime plan before execution. The runner reads that snapshot only. Later edits affect the next run, not the current one.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Make touch geometry visible and honest
&lt;/h2&gt;

&lt;p&gt;If the UI says a tap has a 50 px random range, the marker should show that same range. Users should not have to imagine an invisible sampling area.&lt;/p&gt;

&lt;p&gt;The useful model is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;marker center = configured target&lt;/li&gt;
&lt;li&gt;visible radius = configured random radius&lt;/li&gt;
&lt;li&gt;generated point = always inside that circle&lt;/li&gt;
&lt;li&gt;final point = clamped to the usable display bounds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uniform random sampling inside a circle needs area correction. If u and v are random values in [0, 1), use:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;radius = maxRadius * sqrt(u)
angle = 2 * PI * v
x = centerX + radius * cos(angle)
y = centerY + radius * sin(angle)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Without the square root, points cluster near the center. If you sample X and Y independently in a square, some points fall outside the circle the UI promised.&lt;/p&gt;

&lt;p&gt;The marker itself should not intercept the gesture. On Android overlays, visual layers and touchable control layers should be separated deliberately. A common cause of taps landing above the marker is subtracting the status-bar inset twice or mixing screen coordinates with window coordinates.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Treat every action as its own configuration
&lt;/h2&gt;

&lt;p&gt;A real script is not “choose one global gesture and repeat it.” Each step needs its own data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;action type: tap, double tap, or directional swipe&lt;/li&gt;
&lt;li&gt;start point and optional end point&lt;/li&gt;
&lt;li&gt;random range&lt;/li&gt;
&lt;li&gt;fixed or randomized interval&lt;/li&gt;
&lt;li&gt;delay before the next action&lt;/li&gt;
&lt;li&gt;repeat count, with unlimited as a first-class value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This lets a sequence combine tap, left swipe, another tap, and an upward swipe without inheriting accidental settings from a previous step.&lt;/p&gt;

&lt;p&gt;For swipes, the overlay should display direction and configured distance, but the indicator should not animate along the swipe path. Moving the marker while a script is running makes users think the configured start point changed and can also trigger layout updates at the worst time.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Cancellation is part of the gesture protocol
&lt;/h2&gt;

&lt;p&gt;“Pause” should not just change a button label. It should invalidate every scheduled continuation.&lt;/p&gt;

&lt;p&gt;One practical approach is a monotonically increasing run token:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start: token += 1; runner receives token
pause: token += 1
before every delay or dispatch: stop if local token != current token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That makes stale callbacks harmless. It also prevents the classic bug where an old timer restarts the script after the user has already paused it.&lt;/p&gt;

&lt;p&gt;Android gesture dispatch is asynchronous, so every action also needs a completion path, a cancellation path, and a timeout fallback. The queue must advance exactly once. Put that guarantee in one scheduler component instead of duplicating it across tap and swipe implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Keep overlays stable across apps and rotations
&lt;/h2&gt;

&lt;p&gt;The floating control surface has to survive app switches without becoming a fragile second activity.&lt;/p&gt;

&lt;p&gt;Important details include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the appropriate application overlay window type&lt;/li&gt;
&lt;li&gt;keep window updates on the main thread&lt;/li&gt;
&lt;li&gt;clamp dragged controls to the current display bounds&lt;/li&gt;
&lt;li&gt;recalculate bounds after rotation or configuration changes&lt;/li&gt;
&lt;li&gt;persist only the final drag position, not every movement event&lt;/li&gt;
&lt;li&gt;catch invalid window-token and already-removed-view states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dragging should update only the menu window. Gesture markers should keep their configured coordinates unless the user explicitly moves them.&lt;/p&gt;

&lt;p&gt;Opacity is also a usability feature. Markers need enough contrast to identify “tap,” “double tap,” or swipe direction, but they cannot cover the content users are trying to target. A global opacity setting with a readable minimum works better than fully opaque controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Plan for Android power management
&lt;/h2&gt;

&lt;p&gt;Gesture automation does not automatically guarantee that the display remains awake. Device vendors also apply different battery and background restrictions.&lt;/p&gt;

&lt;p&gt;The app should explain this before a long run, not after it stops. Depending on the use case, a user may need to adjust screen timeout, battery optimization, background activity, or vendor-specific autostart settings. The app should link users into the closest relevant system settings page while leaving the final change under user control.&lt;/p&gt;

&lt;p&gt;A foreground service can keep a user-visible task alive, but it is not a license to run invisibly. The notification should clearly state that an automation session is active and provide a stop action.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Design permission disclosure as product UI
&lt;/h2&gt;

&lt;p&gt;A no-root solution typically relies on Android AccessibilityService for gesture dispatch and overlay permission for controls above other apps. These are sensitive capabilities.&lt;/p&gt;

&lt;p&gt;A good permission flow explains, before opening system settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;what capability is requested&lt;/li&gt;
&lt;li&gt;why the feature cannot work without it&lt;/li&gt;
&lt;li&gt;what data is and is not collected&lt;/li&gt;
&lt;li&gt;how to disable the capability later&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The service should execute only actions the user configured and explicitly started. Script data can remain local. The app should also make prohibited or risky uses clear instead of presenting automation as unlimited.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Debug failures with a deterministic checklist
&lt;/h2&gt;

&lt;p&gt;When an action misses or stops, log the inputs that explain the result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compiled action ID and type&lt;/li&gt;
&lt;li&gt;raw configured coordinates&lt;/li&gt;
&lt;li&gt;window insets and display size&lt;/li&gt;
&lt;li&gt;final sampled and clamped coordinates&lt;/li&gt;
&lt;li&gt;dispatch start, callback, cancellation, and timeout&lt;/li&gt;
&lt;li&gt;current run token&lt;/li&gt;
&lt;li&gt;AccessibilityService and overlay state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That turns “the tap did nothing” into a reproducible geometry or lifecycle problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further practical checklists
&lt;/h2&gt;

&lt;p&gt;Two device-level issues deserve their own checklists because they are easy to miss during implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://phone-operator-site.leelele9.workers.dev/auto-clicker-screen-timeout-battery?utm_source=devto&amp;amp;utm_medium=technical_article&amp;amp;utm_campaign=screen_timeout_battery" rel="noopener noreferrer"&gt;Why Android automation stops when the screen sleeps, and how to prepare for supervised long runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://phone-operator-site.leelele9.workers.dev/accessibility-service-auto-clicker-privacy?utm_source=devto&amp;amp;utm_medium=technical_article&amp;amp;utm_campaign=accessibility_privacy" rel="noopener noreferrer"&gt;How to evaluate AccessibilityService privacy, disclosure, and local-data boundaries in an auto clicker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both guides are based on the same implementation work behind Phone Operator, and they keep the safety and disclosure constraints explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;Reliable Android automation is less about dispatching gestures quickly and more about keeping configuration, geometry, lifecycle, and user trust consistent. The best default is still the simplest one: one fixed tap, unlimited repeats, and an obvious stop control. Advanced mixed scripts should build on that model without making the first run harder.&lt;/p&gt;

&lt;p&gt;I am applying these ideas in &lt;a href="https://play.google.com/store/apps/details?id=com.zidongdianjiqi.app&amp;amp;utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=android_automation" rel="noopener noreferrer"&gt;Phone Operator on Google Play&lt;/a&gt;. I also published practical guides for &lt;a href="https://phone-operator-site.leelele9.workers.dev/android-auto-clicker-no-root?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=android_automation" rel="noopener noreferrer"&gt;no-root setup&lt;/a&gt; and &lt;a href="https://phone-operator-site.leelele9.workers.dev/why-auto-clicker-stops?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=android_automation" rel="noopener noreferrer"&gt;why auto clickers stop&lt;/a&gt;. Feedback about device-specific edge cases is welcome.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>android</category>
      <category>kotlin</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
