├── Android.mk
├── AndroidManifest.xml
├── README.md
├── proguard.flags
├── res
├── drawable-hdpi
│ ├── ic_launcher.png
│ ├── ic_notify_screen_recorder.png
│ ├── ic_notify_screen_recorder_error.png
│ ├── ic_show_touch_disabled.png
│ ├── ic_show_touch_enabled.png
│ └── ic_stop_recording.png
├── drawable-mdpi
│ ├── ic_launcher.png
│ ├── ic_notify_screen_recorder.png
│ ├── ic_notify_screen_recorder_error.png
│ ├── ic_show_touch_disabled.png
│ ├── ic_show_touch_enabled.png
│ └── ic_stop_recording.png
├── drawable-xhdpi
│ ├── ic_launcher.png
│ ├── ic_notify_screen_recorder.png
│ ├── ic_notify_screen_recorder_error.png
│ ├── ic_show_touch_disabled.png
│ ├── ic_show_touch_enabled.png
│ └── ic_stop_recording.png
├── drawable-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_notify_screen_recorder.png
│ ├── ic_notify_screen_recorder_error.png
│ ├── ic_show_touch_disabled.png
│ ├── ic_show_touch_enabled.png
│ └── ic_stop_recording.png
├── values-el
│ └── strings.xml
├── values-sk
│ └── strings.xml
└── values
│ ├── config.xml
│ └── strings.xml
└── src
└── org
└── chameleonos
└── screenrecorder
├── ScreenRecordReceiver.java
└── ScreenRecorderService.java
/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH:= $(call my-dir)
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_MODULE_TAGS := optional
5 |
6 | LOCAL_SRC_FILES := $(call all-java-files-under, src)
7 |
8 | LOCAL_PACKAGE_NAME := ScreenRecorder
9 | LOCAL_CERTIFICATE := platform
10 | LOCAL_PRIVILEGED_MODULE := true
11 |
12 | LOCAL_PROGUARD_FLAG_FILES := proguard.flags
13 |
14 | include $(BUILD_PACKAGE)
15 |
16 | # Use the folloing include to make our test apk.
17 | include $(call all-makefiles-under,$(LOCAL_PATH))
18 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A simple system app that contains a service which interfaces with the ScreenRecorder
2 | class to record video of the device display.
3 |
--------------------------------------------------------------------------------
/proguard.flags:
--------------------------------------------------------------------------------
1 | # Keep all Fragments in this package, which are used by reflection.
2 | -keep class org.chameleonos.screenrecorder.*
3 |
4 | # Keep click responders
5 |
6 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_notify_screen_recorder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-hdpi/ic_notify_screen_recorder.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_notify_screen_recorder_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-hdpi/ic_notify_screen_recorder_error.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_show_touch_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-hdpi/ic_show_touch_disabled.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_show_touch_enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-hdpi/ic_show_touch_enabled.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_stop_recording.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-hdpi/ic_stop_recording.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_notify_screen_recorder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-mdpi/ic_notify_screen_recorder.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_notify_screen_recorder_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-mdpi/ic_notify_screen_recorder_error.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_show_touch_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-mdpi/ic_show_touch_disabled.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_show_touch_enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-mdpi/ic_show_touch_enabled.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_stop_recording.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-mdpi/ic_stop_recording.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_notify_screen_recorder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xhdpi/ic_notify_screen_recorder.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_notify_screen_recorder_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xhdpi/ic_notify_screen_recorder_error.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_show_touch_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xhdpi/ic_show_touch_disabled.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_show_touch_enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xhdpi/ic_show_touch_enabled.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_stop_recording.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xhdpi/ic_stop_recording.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_notify_screen_recorder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xxhdpi/ic_notify_screen_recorder.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_notify_screen_recorder_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xxhdpi/ic_notify_screen_recorder_error.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_show_touch_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xxhdpi/ic_show_touch_disabled.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_show_touch_enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xxhdpi/ic_show_touch_enabled.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_stop_recording.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChameleonOS/android_packages_apps_ScreenRecorder/6ecbef01f584e45992958ea124d74cf65efa9f4b/res/drawable-xxhdpi/ic_stop_recording.png
--------------------------------------------------------------------------------
/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ScreenRecorder
5 |
6 | Η καταγραφή οθόνης βρίσκεται σε εξέλιξη
7 |
8 | Η καταγραφή αποθηκεύτηκε
9 | Πατήστε για να δείτε %s
10 |
11 | Σφάλμα
12 | %s
13 |
14 | Δεν ήταν δυνατή η δημιουργία φακέλου αποθήκευσης.
15 | Δεν υπάρχει εξωτερικός χώρος αποθήκευσης.
16 | Δεν είναι δυνατή η εκκίνηση της καταγραφής.
17 |
18 |
19 |
--------------------------------------------------------------------------------
/res/values-sk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ScreenRecorder
5 |
6 | Prebieha nahrávanie obrazovky
7 |
8 | Nahrávka uložená
9 | Kliknite pre zobrazenie %s
10 |
11 | Chyba
12 | %s
13 |
14 | Nepodarilo sa vytvoriť adresár.
15 | Externé uložisko nie je dostupné.
16 | Nie je možné spustiť nahrávanie.
17 |
18 |
19 |
--------------------------------------------------------------------------------
/res/values/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 720x1280
6 |
7 |
8 | 4000000
9 |
10 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ScreenRecorder
5 |
6 | Screen recording in progress
7 |
8 | Screen recording saved
9 | Touch to view %s
10 |
11 | Screen recorder error
12 | %s
13 |
14 | Processing recorded video
15 |
16 | Stop recording
17 | Show touch
18 |
19 | Unable to create output directory.
20 | No external storage available.
21 | Unable to start recording.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/org/chameleonos/screenrecorder/ScreenRecordReceiver.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2013, The ChameleonOS Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.chameleonos.screenrecorder;
18 |
19 | import android.app.NotificationManager;
20 | import android.content.BroadcastReceiver;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.net.Uri;
24 |
25 | import java.io.File;
26 |
27 | import static org.chameleonos.screenrecorder.ScreenRecorderService.ACTION_NOTIFY_DELETE_SCREENRECORD;
28 | import static org.chameleonos.screenrecorder.ScreenRecorderService.ACTION_NOTIFY_RECORD_SERVICE;
29 | import static org.chameleonos.screenrecorder.ScreenRecorderService.NOTIFICATION_ID;
30 | import static org.chameleonos.screenrecorder.ScreenRecorderService.SCREENRECORD_PATH;
31 |
32 | public class ScreenRecordReceiver extends BroadcastReceiver {
33 |
34 | @Override
35 | public void onReceive(Context context, Intent intent) {
36 | if (ACTION_NOTIFY_RECORD_SERVICE.equals(intent.getAction())) {
37 | Intent serviceIntent = new Intent(context, ScreenRecorderService.class);
38 | serviceIntent.setAction(ACTION_NOTIFY_RECORD_SERVICE);
39 | context.startService(serviceIntent);
40 | } else if (ACTION_NOTIFY_DELETE_SCREENRECORD.equals(intent.getAction())) {
41 | File screenRecord = new File(intent.getExtras().getString(SCREENRECORD_PATH));
42 | if (screenRecord.exists()) screenRecord.delete();
43 | context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
44 | Uri.fromFile(screenRecord)));
45 | NotificationManager notificationManager =
46 | (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
47 | notificationManager.cancel(NOTIFICATION_ID);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/org/chameleonos/screenrecorder/ScreenRecorderService.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2013, The ChameleonOS Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.chameleonos.screenrecorder;
18 |
19 | import android.app.IntentService;
20 | import android.app.Notification;
21 | import android.app.NotificationManager;
22 | import android.app.PendingIntent;
23 | import android.content.ContentResolver;
24 | import android.content.Context;
25 | import android.content.Intent;
26 | import android.content.res.Resources;
27 | import android.graphics.Bitmap;
28 | import android.graphics.Point;
29 | import android.media.MediaActionSound;
30 | import android.media.MediaMetadataRetriever;
31 | import android.media.screenrecorder.ScreenRecorder;
32 | import android.media.screenrecorder.ScreenRecorder.ScreenRecorderCallbacks;
33 | import android.net.Uri;
34 | import android.os.Environment;
35 | import android.provider.Settings;
36 | import android.text.TextUtils;
37 | import android.util.Log;
38 | import android.view.Display;
39 | import android.view.Surface;
40 | import android.view.WindowManager;
41 |
42 | import java.io.File;
43 | import java.text.SimpleDateFormat;
44 | import java.util.Date;
45 |
46 | public class ScreenRecorderService extends IntentService
47 | implements ScreenRecorderCallbacks {
48 | public static final String ACTION_NOTIFY_RECORD_SERVICE
49 | = "org.chameleonos.action.NOTIFY_RECORD_SERVICE";
50 | public static final String ACTION_NOTIFY_DELETE_SCREENRECORD
51 | = "org.chameleonos.action.NOTIFY_DELETE_SCREENRECORD";
52 | public static final String ACTION_NOTIFY_TOGGLE_SHOW_TOUCHES
53 | = "org.chameleonos.action.NOTIFY_TOGGLE_SHOW_TOUCHES";
54 | public static final String SCREENRECORD_PATH
55 | = "org.chameleonos.screenrecorder.SCREENRECORD_PATH";
56 |
57 | private static final String TAG = "ScreenRecorderService";
58 | private static final String RECORDER_FOLDER = "ScreenRecorder";
59 | private static final String RECORDER_PATH =
60 | Environment.getExternalStorageDirectory().getAbsolutePath()
61 | + File.separator + RECORDER_FOLDER;
62 |
63 | public static final int NOTIFICATION_ID = 0xD34D;
64 |
65 | // videos will be saved using SCR_[date]_[time].mp4
66 | private static final String FILE_NAME_FORMAT = "SCR_%s.mp4";
67 | private static final String DATE_TIME_FORMAT = "yyyyMMdd_HHmmss";
68 | private static final String SCREENRECORD_SHARE_SUBJECT_TEMPLATE = "ScreenRecord (%s)";
69 |
70 | private static String sCurrentFileName;
71 | private static ScreenRecorder sScreenRecorder;
72 | private static MediaActionSound sActionSound = new MediaActionSound();
73 |
74 | public ScreenRecorderService() {
75 | super(TAG);
76 | }
77 |
78 | private void startOrStopRecording() {
79 | if (sScreenRecorder == null) {
80 | sScreenRecorder = ScreenRecorder.getInstance();
81 | sScreenRecorder.setScreenRecorderCallbacks(this);
82 | }
83 | final int state = sScreenRecorder.getState();
84 | if (state != ScreenRecorder.STATE_RECORDING) {
85 | startRecording();
86 | } else {
87 | sActionSound.play(MediaActionSound.STOP_VIDEO_RECORDING);
88 | sScreenRecorder.stop();
89 | postProcessingNotification();
90 | }
91 | }
92 |
93 | private static String getVideoFileName() {
94 | final String dateTime;
95 | SimpleDateFormat sdf = new SimpleDateFormat(DATE_TIME_FORMAT);
96 | dateTime = sdf.format(new Date()).toString();
97 |
98 | return String.format(FILE_NAME_FORMAT, dateTime);
99 | }
100 |
101 | private void startRecording() {
102 | // make sure external storage is available first
103 | if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
104 | postRecordingErrorNotification(getString(R.string.error_external_storage_unavailable));
105 | return;
106 | }
107 |
108 | WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
109 | final Display display = wm.getDefaultDisplay();
110 | final int rotation = display.getRotation();
111 | final ContentResolver resolver = getContentResolver();
112 | final Resources res = getResources();
113 |
114 | final int[] dimensions = getVideoDimensions(res, display);
115 | final int bitRate = Settings.System.getInt(resolver,
116 | Settings.System.SCREEN_RECORDER_BITRATE,
117 | res.getInteger(R.integer.config_screenRecorderFramerate));
118 | final boolean recordAudio = Settings.System.getInt(resolver,
119 | Settings.System.SCREEN_RECORDER_RECORD_AUDIO, 0) == 1;
120 |
121 | sScreenRecorder.init(rotation, dimensions[0], dimensions[1], bitRate, 0, recordAudio);
122 | File f = new File(RECORDER_PATH);
123 | if (!f.exists()) {
124 | if (!f.mkdir()) {
125 | Log.e(TAG, "Unable to create output directory " + RECORDER_PATH);
126 | postRecordingErrorNotification(
127 | getString(R.string.error_unable_to_create_directory));
128 | return;
129 | }
130 | }
131 | sCurrentFileName = getVideoFileName();
132 | final String fileName = RECORDER_PATH + File.separator + sCurrentFileName;
133 | Log.d(TAG, "Start recording screen to " + fileName);
134 | try {
135 | if (!sScreenRecorder.start(fileName)) {
136 | postRecordingErrorNotification(getString(R.string.error_unable_to_start));
137 | }
138 | } catch (IllegalStateException e) {
139 | postRecordingErrorNotification(getString(R.string.error_unable_to_start));
140 | }
141 | }
142 |
143 | /* Screen recorder callbacks */
144 | @Override
145 | public void onRecordingStarted() {
146 | final boolean recordAudio = Settings.System.getInt(getContentResolver(),
147 | Settings.System.SCREEN_RECORDER_RECORD_AUDIO, 0) == 1;
148 | // only play the start recording sound when only video is being recorded
149 | // otherwise the sound will be picked up by the mic and included which
150 | // isn't really desirable.
151 | if (!recordAudio) sActionSound.play(MediaActionSound.START_VIDEO_RECORDING);
152 | postRecordingNotification();
153 | }
154 |
155 | @Override
156 | public void onRecordingFinished() {
157 | stopForeground(true);
158 | postRecordingFinishedNotification();
159 | }
160 |
161 | @Override
162 | public void onRecordingError(String error) {
163 | postRecordingErrorNotification(error);
164 | }
165 |
166 | private void postRecordingNotification() {
167 | // set an action for stopping recording
168 | Intent intent = new Intent(ACTION_NOTIFY_RECORD_SERVICE);
169 | PendingIntent stopIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
170 | intent = new Intent(this, ScreenRecorderService.class);
171 |
172 | // set an action for toggling show touches
173 | intent.setAction(ACTION_NOTIFY_TOGGLE_SHOW_TOUCHES);
174 | PendingIntent showTouchesIntent = PendingIntent.getService(this, 0,
175 | intent, 0);
176 | final boolean showTouches = Settings.System.getInt(getContentResolver(),
177 | Settings.System.SHOW_TOUCHES, 0) == 1;
178 | NotificationManager nm =
179 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
180 | Notification notice = new Notification.Builder(this)
181 | .setAutoCancel(false)
182 | .setOngoing(true)
183 | .setContentTitle(getString(R.string.notification_recording_title))
184 | .setSmallIcon(R.drawable.ic_notify_screen_recorder)
185 | .setWhen(System.currentTimeMillis())
186 | .setPriority(Integer.MAX_VALUE)
187 | .addAction(R.drawable.ic_stop_recording,
188 | getString(R.string.notification_action_stop_recording), stopIntent)
189 | .addAction(showTouches ? R.drawable.ic_show_touch_enabled
190 | : R.drawable.ic_show_touch_disabled,
191 | getString(R.string.notification_action_show_touch), showTouchesIntent)
192 | .build();
193 | nm.notify(NOTIFICATION_ID, notice);
194 | }
195 |
196 | private void postProcessingNotification() {
197 | NotificationManager nm =
198 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
199 | Notification notice = new Notification.Builder(this)
200 | .setAutoCancel(true)
201 | .setOngoing(false)
202 | .setContentTitle(getString(R.string.notification_video_processing_title))
203 | .setSmallIcon(R.drawable.ic_notify_screen_recorder)
204 | .setWhen(System.currentTimeMillis())
205 | .build();
206 | nm.notify(NOTIFICATION_ID, notice);
207 | }
208 |
209 | private void postRecordingFinishedNotification() {
210 | long screenRecordTime = System.currentTimeMillis();
211 | Uri uri = Uri.fromFile(new File(RECORDER_PATH + File.separator + sCurrentFileName));
212 | String subjectDate = new SimpleDateFormat("hh:mma, MMM dd, yyyy")
213 | .format(new Date(screenRecordTime));
214 | String subject = String.format(SCREENRECORD_SHARE_SUBJECT_TEMPLATE, subjectDate);
215 | Intent sharingIntent = new Intent(Intent.ACTION_SEND);
216 | sharingIntent.setType("video/mp4");
217 | sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
218 | sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
219 |
220 | Intent chooserIntent = Intent.createChooser(sharingIntent, null);
221 | chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
222 | | Intent.FLAG_ACTIVITY_NEW_TASK);
223 |
224 | Intent deleteIntent = new Intent(ACTION_NOTIFY_DELETE_SCREENRECORD);
225 | deleteIntent.putExtra(SCREENRECORD_PATH, RECORDER_PATH + File.separator + sCurrentFileName);
226 |
227 | Intent intent = new Intent(Intent.ACTION_VIEW);
228 | intent.setDataAndType(uri, "video/mp4");
229 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
230 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
231 | NotificationManager nm =
232 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
233 | Notification.Builder b = new Notification.Builder(this)
234 | .setAutoCancel(true)
235 | .setOngoing(false)
236 | .setContentTitle(getString(R.string.notification_recording_finished_title))
237 | .setContentText(getString(R.string.notification_recording_finished_text,
238 | sCurrentFileName))
239 | .setSmallIcon(R.drawable.ic_notify_screen_recorder)
240 | .setWhen(screenRecordTime)
241 | .setContentIntent(contentIntent)
242 | .addAction(com.android.internal.R.drawable.ic_menu_share,
243 | getString(com.android.internal.R.string.share),
244 | PendingIntent.getActivity(this, 0, chooserIntent,
245 | PendingIntent.FLAG_CANCEL_CURRENT))
246 | .addAction(com.android.internal.R.drawable.ic_menu_delete,
247 | getString(com.android.internal.R.string.delete),
248 | PendingIntent.getBroadcast(this, 0, deleteIntent,
249 | PendingIntent.FLAG_CANCEL_CURRENT));
250 |
251 | // try and grab a frame as a preview
252 | MediaMetadataRetriever mmr = new MediaMetadataRetriever();
253 | mmr.setDataSource(RECORDER_PATH + File.separator + sCurrentFileName);
254 | Bitmap thumbnail = mmr.getFrameAtTime();
255 | if (thumbnail != null) {
256 | Notification.BigPictureStyle style =
257 | new Notification.BigPictureStyle()
258 | .bigPicture(thumbnail)
259 | .setSummaryText(getString(R.string.notification_recording_finished_text,
260 | sCurrentFileName));
261 | b.setStyle(style);
262 | }
263 |
264 | nm.notify(NOTIFICATION_ID, b.build());
265 | }
266 |
267 | private void postRecordingErrorNotification(String error) {
268 | NotificationManager nm =
269 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
270 | Notification notice = new Notification.Builder(this)
271 | .setAutoCancel(true)
272 | .setOngoing(false)
273 | .setContentTitle(getString(R.string.notification_recording_error_title))
274 | .setContentText(getString(R.string.notification_recording_error_text, error))
275 | .setSmallIcon(R.drawable.ic_notify_screen_recorder_error)
276 | .setWhen(System.currentTimeMillis())
277 | .build();
278 | nm.notify(NOTIFICATION_ID, notice);
279 | }
280 |
281 | private int[] getVideoDimensions(Resources res, Display display) {
282 | String dimensionString = Settings.System.getString(getContentResolver(),
283 | Settings.System.SCREEN_RECORDER_OUTPUT_DIMENSIONS);
284 | if (TextUtils.isEmpty(dimensionString)) {
285 | dimensionString = res.getString(R.string.config_screenRecorderOutputDimensions);
286 | }
287 | int[] dimensions = parseDimensions(dimensionString);
288 | if (dimensions == null) {
289 | dimensions = new int[] {720, 1280};
290 | }
291 |
292 | // if rotation is Surface.ROTATION_0 and width>height swap
293 | final Point p = new Point();
294 | display.getRealSize(p);
295 | if (display.getRotation() == Surface.ROTATION_0 && (p.x > p.y)) {
296 | int tmp = dimensions[0];
297 | dimensions[0] = dimensions[1];
298 | dimensions[1] = tmp;
299 | }
300 |
301 | return dimensions;
302 | }
303 |
304 | private static int[] parseDimensions(String dimensions) {
305 | String[] tmp = dimensions.split("x");
306 | if (tmp.length < 2) return null;
307 | int[] dims = new int[2];
308 | try {
309 | dims[0] = Integer.valueOf(tmp[0]);
310 | dims[1] = Integer.valueOf(tmp[1]);
311 | } catch (NumberFormatException e) {
312 | return null;
313 | }
314 |
315 | return dims;
316 | }
317 |
318 | @Override
319 | protected void onHandleIntent(Intent intent) {
320 | final String action = intent.getAction();
321 | if (ACTION_NOTIFY_RECORD_SERVICE.equals(action)) {
322 | startOrStopRecording();
323 | } else if (ACTION_NOTIFY_TOGGLE_SHOW_TOUCHES.equals(action)) {
324 | final boolean showTouches = Settings.System.getInt(getContentResolver(),
325 | Settings.System.SHOW_TOUCHES, 0) == 1;
326 | Settings.System.putInt(getContentResolver(),
327 | Settings.System.SHOW_TOUCHES, showTouches ? 0 : 1);
328 | // call postRecordingNotification so the icon gets updated based on this change
329 | postRecordingNotification();
330 | }
331 | }
332 | }
333 |
--------------------------------------------------------------------------------