+42
.github/workflows/android.yml
+42
.github/workflows/android.yml
···
1
+
name: Android CI
2
+
3
+
on:
4
+
push:
5
+
branches: [ main ]
6
+
pull_request:
7
+
branches: [ main ]
8
+
9
+
jobs:
10
+
build:
11
+
runs-on: ubuntu-latest
12
+
steps:
13
+
- name: Checkout code
14
+
uses: actions/checkout@v4
15
+
16
+
- name: Set up JDK 17
17
+
uses: actions/setup-java@v4
18
+
with:
19
+
distribution: 'temurin'
20
+
java-version: '17'
21
+
22
+
- name: Cache Gradle dependencies
23
+
uses: actions/cache@v4
24
+
with:
25
+
path: |
26
+
~/.gradle/caches
27
+
~/.gradle/wrapper
28
+
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
29
+
restore-keys: |
30
+
gradle-${{ runner.os }}-
31
+
32
+
- name: Grant execute permission for gradlew
33
+
run: chmod +x ./gradlew
34
+
35
+
- name: Build with Gradle
36
+
run: ./gradlew assembleDebug
37
+
38
+
- name: Upload APK artifact
39
+
uses: actions/upload-artifact@v4
40
+
with:
41
+
name: app-debug-apk
42
+
path: app/build/outputs/apk/debug/app-debug.apk
+31
Dockerfile
+31
Dockerfile
···
1
+
FROM eclipse-temurin:17-jdk
2
+
3
+
ENV ANDROID_SDK_ROOT /sdk
4
+
ENV PATH "$PATH:/sdk/cmdline-tools/latest/bin:/sdk/platform-tools:/sdk/emulator"
5
+
6
+
# Install required packages
7
+
RUN apt-get update && apt-get install -y unzip wget git && rm -rf /var/lib/apt/lists/*
8
+
9
+
# Download and install Android SDK command-line tools
10
+
RUN mkdir -p /sdk/cmdline-tools && \
11
+
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /cmdline-tools.zip && \
12
+
unzip /cmdline-tools.zip -d /sdk/cmdline-tools && \
13
+
mv /sdk/cmdline-tools/cmdline-tools /sdk/cmdline-tools/latest && \
14
+
rm /cmdline-tools.zip
15
+
16
+
# Accept licenses and install build tools and platform
17
+
RUN yes | sdkmanager --sdk_root=/sdk --licenses
18
+
RUN sdkmanager --sdk_root=/sdk "platform-tools" "platforms;android-28" "build-tools;34.0.0"
19
+
20
+
# Copy project
21
+
WORKDIR /workspace
22
+
COPY . .
23
+
24
+
# Make gradlew executable
25
+
RUN chmod +x ./gradlew
26
+
27
+
# Build APK
28
+
RUN ./gradlew assembleDebug
29
+
30
+
# Final command: copy APK to /output if mounted
31
+
CMD ["/bin/sh", "-c", "cp app/build/outputs/apk/debug/app-debug.apk /output/ 2>/dev/null || true"]
+29
README.md
+29
README.md
···
1
+
# ShotNShare
2
+
3
+
## Button Mapper Integration
4
+
5
+
To trigger a screenshot from your remote using Button Mapper:
6
+
7
+
1. Open Button Mapper and select the button you want to remap.
8
+
2. Choose "Add action" > "Applications".
9
+
3. Select "ShotNShare ScreenshotActivity" (may appear as just "ScreenshotActivity").
10
+
4. Now, pressing the button will trigger a screenshot and open the share dialog.
11
+
12
+
If you want to trigger via intent, use:
13
+
14
+
```
15
+
Intent action: cl.frabarz.shotnshare.ACTION_TRIGGER_SCREENSHOT
16
+
Component: cl.frabarz.shotnshare/.ScreenshotActivity
17
+
```
18
+
19
+
## Local Container Build
20
+
21
+
To build the APK locally in a container (no Android Studio or SDK needed):
22
+
23
+
```sh
24
+
docker build -t shotnshare-android .
25
+
mkdir -p app/build/outputs/apk/debug
26
+
# Run the build and copy the APK to your host
27
+
# (the APK will appear in ./app/build/outputs/apk/debug)
28
+
docker run --rm -v "$PWD/app/build/outputs/apk/debug:/output" shotnshare-android
29
+
```
+59
SPECS.md
+59
SPECS.md
···
1
+
# ShotNShare: Android TV Screenshot & Share App
2
+
3
+
## Overview
4
+
An Android TV app that enables users to quickly take a screenshot of their current screen and share it via Twitter, WhatsApp, or other supported platforms. The action is triggered by remapping a remote control button for seamless access.
5
+
6
+
---
7
+
8
+
## User Flow
9
+
1. **Trigger**: User presses a remapped button on the Android TV remote.
10
+
2. **Screenshot**: The app captures the current screen.
11
+
3. **Preview & Share**:
12
+
- A simple overlay appears with a preview of the screenshot and sharing options (Twitter, WhatsApp, Copy to Clipboard, etc.).
13
+
- User selects the desired sharing method.
14
+
4. **Share**: The app invokes the chosen sharing intent (e.g., opens Twitter/WhatsApp with the screenshot attached).
15
+
5. **Confirmation**: Optional toast/notification confirming the action.
16
+
17
+
---
18
+
19
+
## Technical Requirements
20
+
- **Platform**: Android TV (API 21+ recommended)
21
+
- **Screenshot Capture**:
22
+
- Use MediaProjection API for screen capture (requires user consent on first use).
23
+
- Handle overlays and system UI appropriately.
24
+
- **Button Remapping**:
25
+
- Support for remapping a remote control button (e.g., via Button Mapper or custom accessibility service).
26
+
- Provide instructions for users to set up remapping.
27
+
- **Sharing**:
28
+
- Integrate with Android's sharing intents for Twitter, WhatsApp, and others.
29
+
- Support for direct sharing to specific apps.
30
+
- **UI/UX**:
31
+
- Minimal, TV-friendly overlay for preview and sharing options.
32
+
- Large, easily navigable buttons.
33
+
- **Permissions**:
34
+
- `FOREGROUND_SERVICE` (for persistent capture service, if needed)
35
+
- `WRITE_EXTERNAL_STORAGE` (for saving screenshots, if required)
36
+
- `INTERNET` (for sharing via social media APIs, if direct integration is added)
37
+
- `CAPTURE_VIDEO_OUTPUT` (if available)
38
+
- `SYSTEM_ALERT_WINDOW` (for overlays, if needed)
39
+
- `BIND_ACCESSIBILITY_SERVICE` (if using accessibility for button remapping)
40
+
- **Error Handling**:
41
+
- Graceful handling of permission denials.
42
+
- User feedback for failed captures or shares.
43
+
- Logging for debugging.
44
+
45
+
---
46
+
47
+
## Extensibility & Future Features
48
+
- Add support for more sharing platforms (Telegram, Facebook, etc.).
49
+
- Allow basic image editing (crop, annotate, blur).
50
+
- Cloud upload (Google Drive, Dropbox, etc.).
51
+
- History of recent screenshots.
52
+
- Customizable overlay UI.
53
+
54
+
---
55
+
56
+
## Notes
57
+
- Some Android TV models may restrict screen capture due to DRM or system limitations.
58
+
- Button remapping may require third-party apps (such as Button Mapper) or accessibility services, as not all remotes are customizable by default. On some Android TVs, the Accessibility service is missing, but Button Mapper can still launch an exported activity or send a broadcast intent to trigger the screenshot action.
59
+
- The app should be modular to allow easy addition of new sharing targets or features.
+25
app/build.gradle
+25
app/build.gradle
···
1
+
plugins {
2
+
id 'com.android.application'
3
+
}
4
+
5
+
android {
6
+
compileSdk 28
7
+
8
+
defaultConfig {
9
+
applicationId "cl.frabarz.shotnshare"
10
+
minSdk 21
11
+
targetSdk 28
12
+
versionCode 1
13
+
versionName "1.0"
14
+
}
15
+
16
+
buildTypes {
17
+
release {
18
+
minifyEnabled false
19
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20
+
}
21
+
}
22
+
}
23
+
24
+
dependencies {
25
+
}
+1
app/proguard-rules.pro
+1
app/proguard-rules.pro
···
1
+
+35
app/src/main/AndroidManifest.xml
+35
app/src/main/AndroidManifest.xml
···
1
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+
package="cl.frabarz.shotnshare">
3
+
4
+
<application
5
+
android:allowBackup="true"
6
+
android:label="ShotNShare"
7
+
android:icon="@mipmap/ic_launcher"
8
+
android:roundIcon="@mipmap/ic_launcher_round"
9
+
android:supportsRtl="true"
10
+
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
11
+
<activity android:name=".MainActivity">
12
+
<intent-filter>
13
+
<action android:name="android.intent.action.MAIN" />
14
+
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
15
+
</intent-filter>
16
+
</activity>
17
+
<activity android:name=".ScreenshotActivity"
18
+
android:exported="true">
19
+
<intent-filter>
20
+
<action android:name="android.intent.action.MAIN" />
21
+
<category android:name="android.intent.category.LAUNCHER" />
22
+
</intent-filter>
23
+
</activity>
24
+
<provider
25
+
android:name="androidx.core.content.FileProvider"
26
+
android:authorities="cl.frabarz.shotnshare.fileprovider"
27
+
android:exported="false"
28
+
android:grantUriPermissions="true">
29
+
<meta-data
30
+
android:name="android.support.FILE_PROVIDER_PATHS"
31
+
android:resource="@xml/file_paths" />
32
+
</provider>
33
+
</application>
34
+
35
+
</manifest>
+29
app/src/main/res/layout/activity_main.xml
+29
app/src/main/res/layout/activity_main.xml
···
1
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
+
android:layout_width="match_parent"
3
+
android:layout_height="match_parent"
4
+
android:orientation="vertical"
5
+
android:gravity="center"
6
+
android:padding="32dp">
7
+
8
+
<Button
9
+
android:id="@+id/btn_capture"
10
+
android:layout_width="wrap_content"
11
+
android:layout_height="wrap_content"
12
+
android:text="Capture Screenshot" />
13
+
14
+
<ImageView
15
+
android:id="@+id/img_preview"
16
+
android:layout_width="320dp"
17
+
android:layout_height="180dp"
18
+
android:layout_marginTop="32dp"
19
+
android:scaleType="fitCenter"
20
+
android:contentDescription="Screenshot Preview" />
21
+
22
+
<Button
23
+
android:id="@+id/btn_share"
24
+
android:layout_width="wrap_content"
25
+
android:layout_height="wrap_content"
26
+
android:layout_marginTop="32dp"
27
+
android:text="Share Screenshot" />
28
+
29
+
</LinearLayout>
+4
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+4
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+4
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+4
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+3
app/src/main/res/values/styles.xml
+3
app/src/main/res/values/styles.xml
+3
app/src/main/res/xml/file_paths.xml
+3
app/src/main/res/xml/file_paths.xml
+16
build.gradle
+16
build.gradle