Revision 41590feb
| app/src/main/AndroidManifest.xml | ||
|---|---|---|
| 15 | 15 |
|
| 16 | 16 |
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher_ssc" |
| 17 | 17 |
android:largeHeap="true" |
| 18 |
android:name=".App" |
|
| 18 |
android:name="org.witness.obscuracam.App"
|
|
| 19 | 19 |
android:theme="@style/AppTheme" |
| 20 | 20 |
> |
| 21 |
<activity android:label="@string/app_name_label" android:name=".MainActivity" |
|
| 21 |
<activity android:label="@string/app_name_label" android:name="org.witness.obscuracam.MainActivity"
|
|
| 22 | 22 |
android:description="@string/app_description" |
| 23 | 23 |
android:configChanges="orientation|keyboardHidden" |
| 24 | 24 |
android:theme="@style/AppTheme.NoActionBar" |
| ... | ... | |
| 28 | 28 |
<category android:name="android.intent.category.LAUNCHER" /> |
| 29 | 29 |
</intent-filter> |
| 30 | 30 |
</activity> |
| 31 |
<activity android:name="org.witness.securesmartcam.ImageEditor"
|
|
| 31 |
<activity android:name="org.witness.obscuracam.ui.ImageEditor"
|
|
| 32 | 32 |
android:configChanges="keyboardHidden|orientation|screenSize" |
| 33 | 33 |
android:theme="@style/AppTheme" |
| 34 | 34 |
> |
| ... | ... | |
| 46 | 46 |
</intent-filter> |
| 47 | 47 |
</activity> |
| 48 | 48 |
|
| 49 |
<activity android:name="org.witness.securesmartcam.ImagePreview" android:label="@string/image_preview" android:configChanges="orientation|keyboardHidden" />
|
|
| 49 |
<activity android:name="org.witness.obscuracam.ui.ImagePreview" android:label="@string/image_preview" android:configChanges="orientation|keyboardHidden" />
|
|
| 50 | 50 |
|
| 51 |
<activity android:name="org.witness.ssc.video.VideoEditor" android:configChanges="orientation|keyboardHidden|screenSize">
|
|
| 51 |
<activity android:name="org.witness.obscuracam.video.VideoEditor" android:configChanges="orientation|keyboardHidden|screenSize">
|
|
| 52 | 52 |
<intent-filter> |
| 53 | 53 |
|
| 54 | 54 |
<action android:name="android.intent.action.EDIT" /> |
| ... | ... | |
| 63 | 63 |
</intent-filter> |
| 64 | 64 |
|
| 65 | 65 |
</activity> |
| 66 |
<activity android:name="org.witness.ssc.video.VideoPreferences" />
|
|
| 66 |
<activity android:name="org.witness.obscuracam.video.VideoPreferences" />
|
|
| 67 | 67 |
<activity |
| 68 |
android:name="org.witness.securesmartcam.AlbumsActivity"
|
|
| 68 |
android:name="org.witness.obscuracam.ui.AlbumsActivity"
|
|
| 69 | 69 |
android:label="@string/title_albums" |
| 70 | 70 |
android:screenOrientation="portrait" |
| 71 | 71 |
android:theme="@style/AppTheme.NoActionBar" |
| app/src/main/java/org/witness/obscuracam/App.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam; |
|
| 2 |
|
|
| 3 |
import android.app.Application; |
|
| 4 |
import android.graphics.Bitmap; |
|
| 5 |
import android.media.ThumbnailUtils; |
|
| 6 |
import android.provider.MediaStore; |
|
| 7 |
|
|
| 8 |
import com.squareup.picasso.Picasso; |
|
| 9 |
import com.squareup.picasso.Request; |
|
| 10 |
import com.squareup.picasso.RequestHandler; |
|
| 11 |
|
|
| 12 |
import java.io.IOException; |
|
| 13 |
|
|
| 14 |
public class App extends Application {
|
|
| 15 |
private static App gInstance; |
|
| 16 |
|
|
| 17 |
public static App getInstance() {
|
|
| 18 |
return gInstance; |
|
| 19 |
} |
|
| 20 |
|
|
| 21 |
@Override |
|
| 22 |
public void onCreate() {
|
|
| 23 |
gInstance = this; |
|
| 24 |
super.onCreate(); |
|
| 25 |
|
|
| 26 |
// Create thumbnails for video |
|
| 27 |
// |
|
| 28 |
Picasso.setSingletonInstance(new Picasso.Builder(this) |
|
| 29 |
.addRequestHandler(new RequestHandler() {
|
|
| 30 |
@Override |
|
| 31 |
public boolean canHandleRequest(Request data) |
|
| 32 |
{
|
|
| 33 |
String scheme = data.uri.getScheme(); |
|
| 34 |
return ("video".equals(scheme));
|
|
| 35 |
} |
|
| 36 |
|
|
| 37 |
@Override |
|
| 38 |
public Result load(Request data, int arg1) throws IOException |
|
| 39 |
{
|
|
| 40 |
String path = data.uri.getPath(); |
|
| 41 |
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MICRO_KIND); |
|
| 42 |
return new Result(bitmap, Picasso.LoadedFrom.DISK); |
|
| 43 |
} |
|
| 44 |
}) |
|
| 45 |
//.indicatorsEnabled(true) |
|
| 46 |
.defaultBitmapConfig(Bitmap.Config.RGB_565) |
|
| 47 |
.build()); |
|
| 48 |
} |
|
| 49 |
} |
|
| app/src/main/java/org/witness/obscuracam/MainActivity.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam; |
|
| 2 |
|
|
| 3 |
|
|
| 4 |
import android.Manifest; |
|
| 5 |
import android.app.AlertDialog; |
|
| 6 |
import android.content.ClipData; |
|
| 7 |
import android.content.Intent; |
|
| 8 |
import android.content.pm.PackageManager; |
|
| 9 |
import android.content.pm.ResolveInfo; |
|
| 10 |
import android.content.res.Configuration; |
|
| 11 |
import android.net.Uri; |
|
| 12 |
import android.os.Build; |
|
| 13 |
import android.os.Bundle; |
|
| 14 |
import android.provider.MediaStore; |
|
| 15 |
import android.support.v4.app.ActivityCompat; |
|
| 16 |
import android.support.v4.content.ContextCompat; |
|
| 17 |
import android.support.v4.content.FileProvider; |
|
| 18 |
import android.support.v7.app.AppCompatActivity; |
|
| 19 |
import android.support.v7.widget.LinearLayoutManager; |
|
| 20 |
import android.support.v7.widget.RecyclerView; |
|
| 21 |
import android.support.v7.widget.Toolbar; |
|
| 22 |
import android.view.Menu; |
|
| 23 |
import android.view.MenuItem; |
|
| 24 |
import android.view.View; |
|
| 25 |
import android.widget.Button; |
|
| 26 |
|
|
| 27 |
import org.witness.obscuracam.ui.AlbumLayoutManager; |
|
| 28 |
import org.witness.obscuracam.ui.AlbumsActivity; |
|
| 29 |
import org.witness.obscuracam.ui.ImageEditor; |
|
| 30 |
import org.witness.obscuracam.ui.adapters.AskForPermissionAdapter; |
|
| 31 |
import org.witness.obscuracam.ui.adapters.GalleryCursorRecyclerViewAdapter; |
|
| 32 |
import org.witness.obscuracam.video.VideoEditor; |
|
| 33 |
import org.witness.sscphase1.R; |
|
| 34 |
|
|
| 35 |
import java.io.File; |
|
| 36 |
import java.io.IOException; |
|
| 37 |
import java.util.List; |
|
| 38 |
|
|
| 39 |
public class MainActivity extends AppCompatActivity implements GalleryCursorRecyclerViewAdapter.GalleryCursorRecyclerViewAdapterListener {
|
|
| 40 |
|
|
| 41 |
public final static String TAG = "SSC"; |
|
| 42 |
|
|
| 43 |
private static final int READ_EXTERNAL_STORAGE_PERMISSION_REQUEST = 1; |
|
| 44 |
private static final int CAPTURE_IMAGE_REQUEST = 2; |
|
| 45 |
private static final int SELECT_FROM_ALBUMS_REQUEST = 3; |
|
| 46 |
|
|
| 47 |
private static final String CAMERA_CAPTURE_DIRNAME = "camera"; |
|
| 48 |
private static final String CAMERA_CAPTURE_FILENAME = "cameracapture"; |
|
| 49 |
|
|
| 50 |
final static int CAMERA_RESULT = 0; |
|
| 51 |
final static int GALLERY_RESULT = 1; |
|
| 52 |
final static int IMAGE_EDITOR = 2; |
|
| 53 |
final static int VIDEO_EDITOR = 3; |
|
| 54 |
final static int ABOUT = 0; |
|
| 55 |
|
|
| 56 |
private RecyclerView recyclerViewPhotos; |
|
| 57 |
private View layoutGalleryInfo; |
|
| 58 |
private AlbumLayoutManager layoutManagerPhotos; |
|
| 59 |
|
|
| 60 |
@Override |
|
| 61 |
protected void onDestroy() |
|
| 62 |
{
|
|
| 63 |
super.onDestroy(); |
|
| 64 |
deleteTmpFile(); |
|
| 65 |
|
|
| 66 |
} |
|
| 67 |
|
|
| 68 |
@Override |
|
| 69 |
public void onCreate(Bundle savedInstanceState) {
|
|
| 70 |
super.onCreate(savedInstanceState); |
|
| 71 |
setContentView(R.layout.activity_main); |
|
| 72 |
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); |
|
| 73 |
setSupportActionBar(toolbar); |
|
| 74 |
deleteTmpFile(); |
|
| 75 |
|
|
| 76 |
layoutGalleryInfo = findViewById(R.id.gallery_info); |
|
| 77 |
Button btnOk = (Button) layoutGalleryInfo.findViewById(R.id.btnGalleryInfoOk); |
|
| 78 |
btnOk.setOnClickListener(new View.OnClickListener() {
|
|
| 79 |
@Override |
|
| 80 |
public void onClick(View view) {
|
|
| 81 |
//TODO App.getInstance().getSettings().setSkipGalleryInfo(true); |
|
| 82 |
layoutGalleryInfo.setVisibility(View.GONE); |
|
| 83 |
} |
|
| 84 |
}); |
|
| 85 |
layoutGalleryInfo.setVisibility(View.GONE); |
|
| 86 |
|
|
| 87 |
recyclerViewPhotos = (RecyclerView) findViewById(R.id.recycler_view_albums); |
|
| 88 |
int colWidth = getResources().getDimensionPixelSize(R.dimen.photo_column_size); |
|
| 89 |
layoutManagerPhotos = new AlbumLayoutManager(this, colWidth); |
|
| 90 |
recyclerViewPhotos.setLayoutManager(layoutManagerPhotos); |
|
| 91 |
|
|
| 92 |
setCurrentMode(); |
|
| 93 |
} |
|
| 94 |
|
|
| 95 |
@Override |
|
| 96 |
protected void onResume() {
|
|
| 97 |
|
|
| 98 |
super.onResume(); |
|
| 99 |
|
|
| 100 |
} |
|
| 101 |
|
|
| 102 |
private void setLayout() {
|
|
| 103 |
setContentView(R.layout.activity_main); |
|
| 104 |
recyclerViewPhotos = (RecyclerView) findViewById(R.id.recycler_view_albums); |
|
| 105 |
} |
|
| 106 |
|
|
| 107 |
/* protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
| 108 |
|
|
| 109 |
|
|
| 110 |
if (resultCode == RESULT_OK) |
|
| 111 |
{
|
|
| 112 |
setContentView(R.layout.mainloading); |
|
| 113 |
|
|
| 114 |
if (requestCode == GALLERY_RESULT) |
|
| 115 |
{
|
|
| 116 |
if (intent != null) |
|
| 117 |
{
|
|
| 118 |
Uri uriGalleryFile = intent.getData(); |
|
| 119 |
|
|
| 120 |
try |
|
| 121 |
{
|
|
| 122 |
if (uriGalleryFile != null) |
|
| 123 |
{
|
|
| 124 |
Cursor cursor = managedQuery(uriGalleryFile, null, |
|
| 125 |
null, null, null); |
|
| 126 |
cursor.moveToNext(); |
|
| 127 |
// Retrieve the path and the mime type |
|
| 128 |
String path = cursor.getString(cursor |
|
| 129 |
.getColumnIndex(MediaStore.MediaColumns.DATA)); |
|
| 130 |
String mimeType = cursor.getString(cursor |
|
| 131 |
.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)); |
|
| 132 |
|
|
| 133 |
if (mimeType == null || mimeType.startsWith("image"))
|
|
| 134 |
{
|
|
| 135 |
Intent passingIntent = new Intent(this,ImageEditor.class); |
|
| 136 |
passingIntent.setData(uriGalleryFile); |
|
| 137 |
startActivityForResult(passingIntent,IMAGE_EDITOR); |
|
| 138 |
} |
|
| 139 |
else if (mimeType.startsWith("video"))
|
|
| 140 |
{
|
|
| 141 |
|
|
| 142 |
Intent passingIntent = new Intent(this,VideoEditor.class); |
|
| 143 |
passingIntent.setData(uriGalleryFile); |
|
| 144 |
startActivityForResult(passingIntent,VIDEO_EDITOR); |
|
| 145 |
} |
|
| 146 |
} |
|
| 147 |
else |
|
| 148 |
{
|
|
| 149 |
Toast.makeText(this, "Unable to load media.", Toast.LENGTH_LONG).show(); |
|
| 150 |
|
|
| 151 |
} |
|
| 152 |
} |
|
| 153 |
catch (Exception e) |
|
| 154 |
{
|
|
| 155 |
Toast.makeText(this, "Unable to load media.", Toast.LENGTH_LONG).show(); |
|
| 156 |
Log.e(TAG, "error loading media: " + e.getMessage(), e); |
|
| 157 |
|
|
| 158 |
} |
|
| 159 |
} |
|
| 160 |
else |
|
| 161 |
{
|
|
| 162 |
Toast.makeText(this, "Unable to load photo.", Toast.LENGTH_LONG).show(); |
|
| 163 |
|
|
| 164 |
} |
|
| 165 |
|
|
| 166 |
} |
|
| 167 |
else if (requestCode == CAMERA_RESULT) |
|
| 168 |
{
|
|
| 169 |
//Uri uriCameraImage = intent.getData(); |
|
| 170 |
|
|
| 171 |
if (uriCameraImage != null) |
|
| 172 |
{
|
|
| 173 |
Intent passingIntent = new Intent(this,ImageEditor.class); |
|
| 174 |
passingIntent.setData(uriCameraImage); |
|
| 175 |
startActivityForResult(passingIntent,IMAGE_EDITOR); |
|
| 176 |
} |
|
| 177 |
else |
|
| 178 |
{
|
|
| 179 |
takePictureButton.setVisibility(View.VISIBLE); |
|
| 180 |
choosePictureButton.setVisibility(View.VISIBLE); |
|
| 181 |
} |
|
| 182 |
} |
|
| 183 |
} |
|
| 184 |
else |
|
| 185 |
setLayout(); |
|
| 186 |
|
|
| 187 |
|
|
| 188 |
|
|
| 189 |
} */ |
|
| 190 |
|
|
| 191 |
/* |
|
| 192 |
* Display the about screen |
|
| 193 |
*/ |
|
| 194 |
private void displayAbout() {
|
|
| 195 |
|
|
| 196 |
StringBuffer msg = new StringBuffer(); |
|
| 197 |
|
|
| 198 |
msg.append(getString(R.string.app_name)); |
|
| 199 |
|
|
| 200 |
String versNum = ""; |
|
| 201 |
|
|
| 202 |
try {
|
|
| 203 |
String pkg = getPackageName(); |
|
| 204 |
versNum = getPackageManager().getPackageInfo(pkg, 0).versionName; |
|
| 205 |
} catch (Exception e) {
|
|
| 206 |
versNum = ""; |
|
| 207 |
} |
|
| 208 |
|
|
| 209 |
msg.append(" v" + versNum);
|
|
| 210 |
msg.append('\n');
|
|
| 211 |
msg.append('\n');
|
|
| 212 |
|
|
| 213 |
msg.append(getString(R.string.about)); |
|
| 214 |
|
|
| 215 |
msg.append('\n');
|
|
| 216 |
msg.append('\n');
|
|
| 217 |
|
|
| 218 |
msg.append(getString(R.string.about2)); |
|
| 219 |
|
|
| 220 |
msg.append('\n');
|
|
| 221 |
msg.append('\n');
|
|
| 222 |
|
|
| 223 |
msg.append(getString(R.string.about3)); |
|
| 224 |
|
|
| 225 |
showDialog(msg.toString()); |
|
| 226 |
} |
|
| 227 |
|
|
| 228 |
private void showDialog (String msg) |
|
| 229 |
{
|
|
| 230 |
new AlertDialog.Builder(this) |
|
| 231 |
.setTitle(getString(R.string.app_name)) |
|
| 232 |
.setMessage(msg) |
|
| 233 |
.create().show(); |
|
| 234 |
} |
|
| 235 |
|
|
| 236 |
|
|
| 237 |
@Override |
|
| 238 |
public boolean onCreateOptionsMenu(Menu menu) {
|
|
| 239 |
|
|
| 240 |
String aboutString = "About ObscuraCam"; |
|
| 241 |
|
|
| 242 |
MenuItem aboutMenuItem = menu.add(Menu.NONE, ABOUT, Menu.NONE, aboutString); |
|
| 243 |
aboutMenuItem.setIcon(R.drawable.ic_menu_about); |
|
| 244 |
|
|
| 245 |
|
|
| 246 |
return true; |
|
| 247 |
} |
|
| 248 |
|
|
| 249 |
public boolean onOptionsItemSelected(MenuItem item) {
|
|
| 250 |
switch (item.getItemId()) {
|
|
| 251 |
case ABOUT: |
|
| 252 |
displayAbout(); |
|
| 253 |
return true; |
|
| 254 |
|
|
| 255 |
default: |
|
| 256 |
|
|
| 257 |
return false; |
|
| 258 |
} |
|
| 259 |
} |
|
| 260 |
|
|
| 261 |
|
|
| 262 |
/* |
|
| 263 |
* Handling screen configuration changes ourselves, |
|
| 264 |
* we don't want the activity to restart on rotation |
|
| 265 |
*/ |
|
| 266 |
@Override |
|
| 267 |
public void onConfigurationChanged(Configuration conf) |
|
| 268 |
{
|
|
| 269 |
super.onConfigurationChanged(conf); |
|
| 270 |
// Reset the layout to use the landscape config |
|
| 271 |
setLayout(); |
|
| 272 |
} |
|
| 273 |
|
|
| 274 |
private void setCurrentMode() {
|
|
| 275 |
int permissionCheck = ContextCompat.checkSelfPermission(this, |
|
| 276 |
Manifest.permission.READ_EXTERNAL_STORAGE); |
|
| 277 |
if (Build.VERSION.SDK_INT <= 18) |
|
| 278 |
permissionCheck = PackageManager.PERMISSION_GRANTED; // For old devices we ask in the manifest! |
|
| 279 |
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
|
|
| 280 |
AskForPermissionAdapter adapter = new AskForPermissionAdapter(this); |
|
| 281 |
recyclerViewPhotos.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); |
|
| 282 |
recyclerViewPhotos.setAdapter(adapter); |
|
| 283 |
} else {
|
|
| 284 |
applyCurrentMode(); |
|
| 285 |
} |
|
| 286 |
} |
|
| 287 |
|
|
| 288 |
public void askForReadExternalStoragePermission() {
|
|
| 289 |
ActivityCompat.requestPermissions(this, new String[]{
|
|
| 290 |
Manifest.permission.READ_EXTERNAL_STORAGE, |
|
| 291 |
Manifest.permission.WRITE_EXTERNAL_STORAGE |
|
| 292 |
}, |
|
| 293 |
READ_EXTERNAL_STORAGE_PERMISSION_REQUEST); |
|
| 294 |
} |
|
| 295 |
|
|
| 296 |
@Override |
|
| 297 |
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
|
|
| 298 |
switch (requestCode) {
|
|
| 299 |
case READ_EXTERNAL_STORAGE_PERMISSION_REQUEST: {
|
|
| 300 |
// If request is cancelled, the result arrays are empty. |
|
| 301 |
if (grantResults.length > 1 |
|
| 302 |
&& grantResults[0] == PackageManager.PERMISSION_GRANTED |
|
| 303 |
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
|
|
| 304 |
applyCurrentMode(); |
|
| 305 |
} |
|
| 306 |
} |
|
| 307 |
break; |
|
| 308 |
} |
|
| 309 |
} |
|
| 310 |
|
|
| 311 |
private void applyCurrentMode() {
|
|
| 312 |
//TODO layoutGalleryInfo.setVisibility(App.getInstance().getSettings().skipGalleryInfo() ? View.GONE : View.VISIBLE); |
|
| 313 |
setPhotosAdapter(null, true, true); |
|
| 314 |
} |
|
| 315 |
|
|
| 316 |
private void setPhotosAdapter(String album, boolean showCamera, boolean showAlbums) {
|
|
| 317 |
recyclerViewPhotos.setLayoutManager(layoutManagerPhotos); |
|
| 318 |
GalleryCursorRecyclerViewAdapter adapter = new GalleryCursorRecyclerViewAdapter(this, album, showCamera, showAlbums); |
|
| 319 |
adapter.setListener(this); |
|
| 320 |
int colWidth = getResources().getDimensionPixelSize(R.dimen.photo_column_size); |
|
| 321 |
layoutManagerPhotos.setColumnWidth(colWidth); |
|
| 322 |
recyclerViewPhotos.setAdapter(adapter); |
|
| 323 |
} |
|
| 324 |
|
|
| 325 |
@Override |
|
| 326 |
public void onPhotoSelected(String photo, View thumbView) {
|
|
| 327 |
final Uri uri = Uri.parse(photo); |
|
| 328 |
if (uri != null) {
|
|
| 329 |
try {
|
|
| 330 |
Intent passingIntent = new Intent(this, ImageEditor.class); |
|
| 331 |
passingIntent.setData(uri); |
|
| 332 |
startActivityForResult(passingIntent, IMAGE_EDITOR); |
|
| 333 |
} catch (Exception e) {
|
|
| 334 |
e.printStackTrace(); |
|
| 335 |
} |
|
| 336 |
} |
|
| 337 |
} |
|
| 338 |
|
|
| 339 |
@Override |
|
| 340 |
public void onVideoSelected(String photo, View thumbView) {
|
|
| 341 |
final Uri uri = Uri.parse(photo); |
|
| 342 |
if (uri != null) {
|
|
| 343 |
try {
|
|
| 344 |
Intent passingIntent = new Intent(this, VideoEditor.class); |
|
| 345 |
passingIntent.setData(uri); |
|
| 346 |
startActivityForResult(passingIntent, VIDEO_EDITOR); |
|
| 347 |
} catch (Exception e) {
|
|
| 348 |
e.printStackTrace(); |
|
| 349 |
} |
|
| 350 |
} |
|
| 351 |
} |
|
| 352 |
|
|
| 353 |
@Override |
|
| 354 |
public void onCameraSelected() {
|
|
| 355 |
takePicture(); |
|
| 356 |
} |
|
| 357 |
|
|
| 358 |
@Override |
|
| 359 |
public void onAlbumsSelected() {
|
|
| 360 |
Intent intentAlbums = new Intent(this, AlbumsActivity.class); |
|
| 361 |
startActivityForResult(intentAlbums, SELECT_FROM_ALBUMS_REQUEST); |
|
| 362 |
} |
|
| 363 |
|
|
| 364 |
private void takePicture() {
|
|
| 365 |
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); |
|
| 366 |
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
|
|
| 367 |
|
|
| 368 |
try {
|
|
| 369 |
File storageDir = new File(getCacheDir(), CAMERA_CAPTURE_DIRNAME); |
|
| 370 |
if (!storageDir.exists()) {
|
|
| 371 |
storageDir.mkdir(); |
|
| 372 |
} |
|
| 373 |
File image = new File(storageDir, CAMERA_CAPTURE_FILENAME); |
|
| 374 |
if (image.exists()) {
|
|
| 375 |
image.delete(); |
|
| 376 |
} |
|
| 377 |
image.createNewFile(); |
|
| 378 |
|
|
| 379 |
Uri photoURI = FileProvider.getUriForFile(this, |
|
| 380 |
"org.witness.securesmartcam.camera_capture", |
|
| 381 |
image); |
|
| 382 |
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); |
|
| 383 |
|
|
| 384 |
// Need to grant uri permissions, see here: |
|
| 385 |
// http://stackoverflow.com/questions/33650632/fileprovider-not-working-with-camera |
|
| 386 |
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) {
|
|
| 387 |
takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); |
|
| 388 |
} |
|
| 389 |
else if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN) {
|
|
| 390 |
ClipData clip= |
|
| 391 |
ClipData.newUri(getContentResolver(), "A photo", photoURI); |
|
| 392 |
|
|
| 393 |
takePictureIntent.setClipData(clip); |
|
| 394 |
takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); |
|
| 395 |
} |
|
| 396 |
else {
|
|
| 397 |
List<ResolveInfo> resInfoList= |
|
| 398 |
getPackageManager() |
|
| 399 |
.queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY); |
|
| 400 |
|
|
| 401 |
for (ResolveInfo resolveInfo : resInfoList) {
|
|
| 402 |
String packageName = resolveInfo.activityInfo.packageName; |
|
| 403 |
grantUriPermission(packageName, photoURI, |
|
| 404 |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION); |
|
| 405 |
} |
|
| 406 |
} |
|
| 407 |
|
|
| 408 |
startActivityForResult(takePictureIntent, CAPTURE_IMAGE_REQUEST); |
|
| 409 |
} catch (IOException ignored) {
|
|
| 410 |
} |
|
| 411 |
} |
|
| 412 |
} |
|
| 413 |
|
|
| 414 |
@Override |
|
| 415 |
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
| 416 |
if (requestCode == CAPTURE_IMAGE_REQUEST && resultCode == RESULT_OK) {
|
|
| 417 |
try {
|
|
| 418 |
File storageDir = new File(getCacheDir(), CAMERA_CAPTURE_DIRNAME); |
|
| 419 |
File image = new File(storageDir, CAMERA_CAPTURE_FILENAME); |
|
| 420 |
if (image.exists()) {
|
|
| 421 |
onPhotoSelected(image.getAbsolutePath(), null); |
|
| 422 |
//TODO image.delete(); |
|
| 423 |
} |
|
| 424 |
} catch (Exception ignored) {
|
|
| 425 |
} |
|
| 426 |
} else if (requestCode == SELECT_FROM_ALBUMS_REQUEST) {
|
|
| 427 |
if (resultCode == RESULT_OK && data != null && data.hasExtra("uri")) {
|
|
| 428 |
boolean isVideo = data.getBooleanExtra("video", false);
|
|
| 429 |
if (isVideo) {
|
|
| 430 |
onVideoSelected(data.getStringExtra("uri"), null);
|
|
| 431 |
} else {
|
|
| 432 |
onPhotoSelected(data.getStringExtra("uri"), null);
|
|
| 433 |
} |
|
| 434 |
} |
|
| 435 |
} |
|
| 436 |
} |
|
| 437 |
|
|
| 438 |
private void deleteTmpFile () |
|
| 439 |
{
|
|
| 440 |
try {
|
|
| 441 |
File storageDir = new File(getCacheDir(), CAMERA_CAPTURE_DIRNAME); |
|
| 442 |
if (!storageDir.exists()) {
|
|
| 443 |
storageDir.mkdir(); |
|
| 444 |
} |
|
| 445 |
File image = new File(storageDir, CAMERA_CAPTURE_FILENAME); |
|
| 446 |
if (image.exists()) {
|
|
| 447 |
image.delete(); |
|
| 448 |
} |
|
| 449 |
} catch (Exception ignored) {}
|
|
| 450 |
} |
|
| 451 |
} |
|
| app/src/main/java/org/witness/obscuracam/ObscuraApp.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam; |
|
| 2 |
|
|
| 3 |
|
|
| 4 |
|
|
| 5 |
import java.io.File; |
|
| 6 |
|
|
| 7 |
import org.witness.obscuracam.ui.AlbumsActivity; |
|
| 8 |
import org.witness.obscuracam.ui.ImageEditor; |
|
| 9 |
import org.witness.obscuracam.video.VideoEditor; |
|
| 10 |
import org.witness.sscphase1.R; |
|
| 11 |
|
|
| 12 |
import android.app.AlertDialog; |
|
| 13 |
import android.content.ContentValues; |
|
| 14 |
import android.content.Intent; |
|
| 15 |
import android.content.res.Configuration; |
|
| 16 |
import android.database.Cursor; |
|
| 17 |
import android.net.Uri; |
|
| 18 |
import android.os.Bundle; |
|
| 19 |
import android.os.Environment; |
|
| 20 |
import android.provider.MediaStore; |
|
| 21 |
import android.support.v7.app.AppCompatActivity; |
|
| 22 |
import android.util.Log; |
|
| 23 |
import android.view.Menu; |
|
| 24 |
import android.view.MenuItem; |
|
| 25 |
import android.view.View; |
|
| 26 |
import android.view.View.OnClickListener; |
|
| 27 |
import android.view.Window; |
|
| 28 |
import android.widget.Button; |
|
| 29 |
import android.widget.Toast; |
|
| 30 |
|
|
| 31 |
public class ObscuraApp extends AppCompatActivity implements OnClickListener {
|
|
| 32 |
|
|
| 33 |
public final static String TAG = "SSC"; |
|
| 34 |
|
|
| 35 |
final static int CAMERA_RESULT = 0; |
|
| 36 |
final static int GALLERY_RESULT = 1; |
|
| 37 |
final static int IMAGE_EDITOR = 2; |
|
| 38 |
final static int VIDEO_EDITOR = 3; |
|
| 39 |
final static int ABOUT = 0; |
|
| 40 |
|
|
| 41 |
final static String CAMERA_TMP_FILE = "ssctmp.jpg"; |
|
| 42 |
|
|
| 43 |
private Button choosePictureButton, chooseVideoButton, takePictureButton; |
|
| 44 |
|
|
| 45 |
private Uri uriCameraImage = null; |
|
| 46 |
|
|
| 47 |
@Override |
|
| 48 |
protected void onDestroy() |
|
| 49 |
{
|
|
| 50 |
super.onDestroy(); |
|
| 51 |
deleteTmpFile(); |
|
| 52 |
|
|
| 53 |
} |
|
| 54 |
|
|
| 55 |
private void deleteTmpFile () |
|
| 56 |
{
|
|
| 57 |
File fileDir = getExternalFilesDir(null); |
|
| 58 |
|
|
| 59 |
if (fileDir == null || !fileDir.exists()) |
|
| 60 |
fileDir = getFilesDir(); |
|
| 61 |
|
|
| 62 |
File tmpFile = new File(fileDir,CAMERA_TMP_FILE); |
|
| 63 |
if (tmpFile.exists()) |
|
| 64 |
tmpFile.delete(); |
|
| 65 |
} |
|
| 66 |
|
|
| 67 |
|
|
| 68 |
|
|
| 69 |
@Override |
|
| 70 |
public void onCreate(Bundle savedInstanceState) {
|
|
| 71 |
super.onCreate(savedInstanceState); |
|
| 72 |
|
|
| 73 |
requestWindowFeature(Window.FEATURE_NO_TITLE); |
|
| 74 |
|
|
| 75 |
setLayout(); |
|
| 76 |
deleteTmpFile(); |
|
| 77 |
|
|
| 78 |
} |
|
| 79 |
|
|
| 80 |
@Override |
|
| 81 |
protected void onResume() {
|
|
| 82 |
|
|
| 83 |
super.onResume(); |
|
| 84 |
|
|
| 85 |
|
|
| 86 |
} |
|
| 87 |
|
|
| 88 |
private void setLayout() {
|
|
| 89 |
|
|
| 90 |
setContentView(R.layout.mainmenu); |
|
| 91 |
|
|
| 92 |
choosePictureButton = (Button) this.findViewById(R.id.ChoosePictureButton); |
|
| 93 |
choosePictureButton.setOnClickListener(this); |
|
| 94 |
|
|
| 95 |
chooseVideoButton = (Button) this.findViewById(R.id.ChooseVideoButton); |
|
| 96 |
chooseVideoButton.setOnClickListener(this); |
|
| 97 |
|
|
| 98 |
takePictureButton = (Button) this.findViewById(R.id.TakePictureButton); |
|
| 99 |
takePictureButton.setOnClickListener(this); |
|
| 100 |
|
|
| 101 |
} |
|
| 102 |
|
|
| 103 |
public void onClick(View v) {
|
|
| 104 |
if (v == choosePictureButton) |
|
| 105 |
{
|
|
| 106 |
Intent intentAlbums = new Intent(this, AlbumsActivity.class); |
|
| 107 |
startActivityForResult(intentAlbums, 4711); //SELECT_FROM_ALBUMS_REQUEST); |
|
| 108 |
// try |
|
| 109 |
// {
|
|
| 110 |
// setContentView(R.layout.mainloading); |
|
| 111 |
// Intent intent = new Intent(Intent.ACTION_PICK); |
|
| 112 |
// intent.setType("image/*"); //limit to image types for now
|
|
| 113 |
// startActivityForResult(intent, GALLERY_RESULT); |
|
| 114 |
// |
|
| 115 |
// } |
|
| 116 |
// catch (Exception e) |
|
| 117 |
// {
|
|
| 118 |
// Toast.makeText(this, "Unable to open Gallery app", Toast.LENGTH_LONG).show(); |
|
| 119 |
// Log.e(TAG, "error loading gallery app to choose photo: " + e.getMessage(), e); |
|
| 120 |
// } |
|
| 121 |
|
|
| 122 |
} |
|
| 123 |
else if (v == chooseVideoButton) |
|
| 124 |
{
|
|
| 125 |
|
|
| 126 |
try |
|
| 127 |
{
|
|
| 128 |
setContentView(R.layout.mainloading); |
|
| 129 |
Intent intent = new Intent(Intent.ACTION_PICK); |
|
| 130 |
intent.setType("video/*"); //limit to image types for now
|
|
| 131 |
startActivityForResult(intent, GALLERY_RESULT); |
|
| 132 |
|
|
| 133 |
} |
|
| 134 |
catch (Exception e) |
|
| 135 |
{
|
|
| 136 |
Toast.makeText(this, "Unable to open Gallery app", Toast.LENGTH_LONG).show(); |
|
| 137 |
Log.e(TAG, "error loading gallery app to choose photo: " + e.getMessage(), e); |
|
| 138 |
} |
|
| 139 |
|
|
| 140 |
} |
|
| 141 |
else if (v == takePictureButton) {
|
|
| 142 |
|
|
| 143 |
setContentView(R.layout.mainloading); |
|
| 144 |
|
|
| 145 |
String storageState = Environment.getExternalStorageState(); |
|
| 146 |
if(storageState.equals(Environment.MEDIA_MOUNTED)) {
|
|
| 147 |
|
|
| 148 |
|
|
| 149 |
ContentValues values = new ContentValues(); |
|
| 150 |
|
|
| 151 |
values.put(MediaStore.Images.Media.TITLE, CAMERA_TMP_FILE); |
|
| 152 |
|
|
| 153 |
values.put(MediaStore.Images.Media.DESCRIPTION,"ssctmp"); |
|
| 154 |
|
|
| 155 |
File tmpFileDirectory = new File(Environment.getExternalStorageDirectory().getPath() + ImageEditor.TMP_FILE_DIRECTORY); |
|
| 156 |
if (!tmpFileDirectory.exists()) |
|
| 157 |
tmpFileDirectory.mkdirs(); |
|
| 158 |
|
|
| 159 |
File tmpFile = new File(tmpFileDirectory,"cam" + ImageEditor.TMP_FILE_NAME); |
|
| 160 |
|
|
| 161 |
uriCameraImage = Uri.fromFile(tmpFile); |
|
| 162 |
//uriCameraImage = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); |
|
| 163 |
|
|
| 164 |
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE ); |
|
| 165 |
intent.putExtra( MediaStore.EXTRA_OUTPUT, uriCameraImage); |
|
| 166 |
|
|
| 167 |
startActivityForResult(intent, CAMERA_RESULT); |
|
| 168 |
} else {
|
|
| 169 |
new AlertDialog.Builder(ObscuraApp.this) |
|
| 170 |
.setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState)
|
|
| 171 |
.setCancelable(true).create().show(); |
|
| 172 |
} |
|
| 173 |
|
|
| 174 |
takePictureButton.setVisibility(View.VISIBLE); |
|
| 175 |
choosePictureButton.setVisibility(View.VISIBLE); |
|
| 176 |
chooseVideoButton.setVisibility(View.VISIBLE); |
|
| 177 |
|
|
| 178 |
} |
|
| 179 |
} |
|
| 180 |
|
|
| 181 |
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
| 182 |
|
|
| 183 |
|
|
| 184 |
if (resultCode == RESULT_OK) |
|
| 185 |
{
|
|
| 186 |
setContentView(R.layout.mainloading); |
|
| 187 |
|
|
| 188 |
if (requestCode == GALLERY_RESULT) |
|
| 189 |
{
|
|
| 190 |
if (intent != null) |
|
| 191 |
{
|
|
| 192 |
Uri uriGalleryFile = intent.getData(); |
|
| 193 |
|
|
| 194 |
try |
|
| 195 |
{
|
|
| 196 |
if (uriGalleryFile != null) |
|
| 197 |
{
|
|
| 198 |
Cursor cursor = managedQuery(uriGalleryFile, null, |
|
| 199 |
null, null, null); |
|
| 200 |
cursor.moveToNext(); |
|
| 201 |
// Retrieve the path and the mime type |
|
| 202 |
String path = cursor.getString(cursor |
|
| 203 |
.getColumnIndex(MediaStore.MediaColumns.DATA)); |
|
| 204 |
String mimeType = cursor.getString(cursor |
|
| 205 |
.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE)); |
|
| 206 |
|
|
| 207 |
if (mimeType == null || mimeType.startsWith("image"))
|
|
| 208 |
{
|
|
| 209 |
Intent passingIntent = new Intent(this,ImageEditor.class); |
|
| 210 |
passingIntent.setData(uriGalleryFile); |
|
| 211 |
startActivityForResult(passingIntent,IMAGE_EDITOR); |
|
| 212 |
} |
|
| 213 |
else if (mimeType.startsWith("video"))
|
|
| 214 |
{
|
|
| 215 |
|
|
| 216 |
Intent passingIntent = new Intent(this,VideoEditor.class); |
|
| 217 |
passingIntent.setData(uriGalleryFile); |
|
| 218 |
startActivityForResult(passingIntent,VIDEO_EDITOR); |
|
| 219 |
} |
|
| 220 |
} |
|
| 221 |
else |
|
| 222 |
{
|
|
| 223 |
Toast.makeText(this, "Unable to load media.", Toast.LENGTH_LONG).show(); |
|
| 224 |
|
|
| 225 |
} |
|
| 226 |
} |
|
| 227 |
catch (Exception e) |
|
| 228 |
{
|
|
| 229 |
Toast.makeText(this, "Unable to load media.", Toast.LENGTH_LONG).show(); |
|
| 230 |
Log.e(TAG, "error loading media: " + e.getMessage(), e); |
|
| 231 |
|
|
| 232 |
} |
|
| 233 |
} |
|
| 234 |
else |
|
| 235 |
{
|
|
| 236 |
Toast.makeText(this, "Unable to load photo.", Toast.LENGTH_LONG).show(); |
|
| 237 |
|
|
| 238 |
} |
|
| 239 |
|
|
| 240 |
} |
|
| 241 |
else if (requestCode == CAMERA_RESULT) |
|
| 242 |
{
|
|
| 243 |
//Uri uriCameraImage = intent.getData(); |
|
| 244 |
|
|
| 245 |
if (uriCameraImage != null) |
|
| 246 |
{
|
|
| 247 |
Intent passingIntent = new Intent(this,ImageEditor.class); |
|
| 248 |
passingIntent.setData(uriCameraImage); |
|
| 249 |
startActivityForResult(passingIntent,IMAGE_EDITOR); |
|
| 250 |
} |
|
| 251 |
else |
|
| 252 |
{
|
|
| 253 |
takePictureButton.setVisibility(View.VISIBLE); |
|
| 254 |
choosePictureButton.setVisibility(View.VISIBLE); |
|
| 255 |
} |
|
| 256 |
} |
|
| 257 |
} |
|
| 258 |
else |
|
| 259 |
setLayout(); |
|
| 260 |
|
|
| 261 |
|
|
| 262 |
|
|
| 263 |
} |
|
| 264 |
|
|
| 265 |
/* |
|
| 266 |
* Display the about screen |
|
| 267 |
*/ |
|
| 268 |
private void displayAbout() {
|
|
| 269 |
|
|
| 270 |
StringBuffer msg = new StringBuffer(); |
|
| 271 |
|
|
| 272 |
msg.append(getString(R.string.app_name)); |
|
| 273 |
|
|
| 274 |
String versNum = ""; |
|
| 275 |
|
|
| 276 |
try {
|
|
| 277 |
String pkg = getPackageName(); |
|
| 278 |
versNum = getPackageManager().getPackageInfo(pkg, 0).versionName; |
|
| 279 |
} catch (Exception e) {
|
|
| 280 |
versNum = ""; |
|
| 281 |
} |
|
| 282 |
|
|
| 283 |
msg.append(" v" + versNum);
|
|
| 284 |
msg.append('\n');
|
|
| 285 |
msg.append('\n');
|
|
| 286 |
|
|
| 287 |
msg.append(getString(R.string.about)); |
|
| 288 |
|
|
| 289 |
msg.append('\n');
|
|
| 290 |
msg.append('\n');
|
|
| 291 |
|
|
| 292 |
msg.append(getString(R.string.about2)); |
|
| 293 |
|
|
| 294 |
msg.append('\n');
|
|
| 295 |
msg.append('\n');
|
|
| 296 |
|
|
| 297 |
msg.append(getString(R.string.about3)); |
|
| 298 |
|
|
| 299 |
showDialog(msg.toString()); |
|
| 300 |
} |
|
| 301 |
|
|
| 302 |
private void showDialog (String msg) |
|
| 303 |
{
|
|
| 304 |
new AlertDialog.Builder(this) |
|
| 305 |
.setTitle(getString(R.string.app_name)) |
|
| 306 |
.setMessage(msg) |
|
| 307 |
.create().show(); |
|
| 308 |
} |
|
| 309 |
|
|
| 310 |
|
|
| 311 |
@Override |
|
| 312 |
public boolean onCreateOptionsMenu(Menu menu) {
|
|
| 313 |
|
|
| 314 |
String aboutString = "About ObscuraCam"; |
|
| 315 |
|
|
| 316 |
MenuItem aboutMenuItem = menu.add(Menu.NONE, ABOUT, Menu.NONE, aboutString); |
|
| 317 |
aboutMenuItem.setIcon(R.drawable.ic_menu_about); |
|
| 318 |
|
|
| 319 |
|
|
| 320 |
return true; |
|
| 321 |
} |
|
| 322 |
|
|
| 323 |
public boolean onOptionsItemSelected(MenuItem item) {
|
|
| 324 |
switch (item.getItemId()) {
|
|
| 325 |
case ABOUT: |
|
| 326 |
displayAbout(); |
|
| 327 |
return true; |
|
| 328 |
|
|
| 329 |
default: |
|
| 330 |
|
|
| 331 |
return false; |
|
| 332 |
} |
|
| 333 |
} |
|
| 334 |
|
|
| 335 |
|
|
| 336 |
/* |
|
| 337 |
* Handling screen configuration changes ourselves, |
|
| 338 |
* we don't want the activity to restart on rotation |
|
| 339 |
*/ |
|
| 340 |
@Override |
|
| 341 |
public void onConfigurationChanged(Configuration conf) |
|
| 342 |
{
|
|
| 343 |
super.onConfigurationChanged(conf); |
|
| 344 |
// Reset the layout to use the landscape config |
|
| 345 |
setLayout(); |
|
| 346 |
} |
|
| 347 |
|
|
| 348 |
|
|
| 349 |
} |
|
| app/src/main/java/org/witness/obscuracam/photo/detect/AndroidFaceDetection.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam.photo.detect; |
|
| 2 |
|
|
| 3 |
import java.util.ArrayList; |
|
| 4 |
|
|
| 5 |
import android.graphics.Bitmap; |
|
| 6 |
import android.graphics.PointF; |
|
| 7 |
import android.graphics.RectF; |
|
| 8 |
import android.media.FaceDetector; |
|
| 9 |
import android.media.FaceDetector.Face; |
|
| 10 |
|
|
| 11 |
public class AndroidFaceDetection implements FaceDetection {
|
|
| 12 |
|
|
| 13 |
public static final String LOGTAG = "AndroidFaceDetection"; |
|
| 14 |
|
|
| 15 |
public static int MAX_FACES = 10; |
|
| 16 |
|
|
| 17 |
Face[] faces = new Face[MAX_FACES]; |
|
| 18 |
FaceDetector faceDetector; |
|
| 19 |
|
|
| 20 |
int numFaces = 0; |
|
| 21 |
|
|
| 22 |
public final static float CONFIDENCE_FILTER = .15f; |
|
| 23 |
|
|
| 24 |
public AndroidFaceDetection(int width, int height) {
|
|
| 25 |
|
|
| 26 |
faceDetector = new FaceDetector(width, height, MAX_FACES); |
|
| 27 |
|
|
| 28 |
} |
|
| 29 |
|
|
| 30 |
public void release () |
|
| 31 |
{
|
|
| 32 |
faceDetector = null; |
|
| 33 |
} |
|
| 34 |
|
|
| 35 |
public int findFaces(Bitmap bmp) {
|
|
| 36 |
|
|
| 37 |
numFaces = faceDetector.findFaces(bmp, faces); |
|
| 38 |
return numFaces; |
|
| 39 |
} |
|
| 40 |
|
|
| 41 |
public ArrayList<DetectedFace> getFaces(int foundFaces) {
|
|
| 42 |
|
|
| 43 |
ArrayList<DetectedFace> dFaces = new ArrayList<DetectedFace>(); |
|
| 44 |
|
|
| 45 |
for (int i = 0; i < foundFaces; i++) {
|
|
| 46 |
|
|
| 47 |
if (faces[i].confidence() > CONFIDENCE_FILTER) |
|
| 48 |
{
|
|
| 49 |
PointF midPoint = new PointF(); |
|
| 50 |
|
|
| 51 |
float eyeDistance = faces[i].eyesDistance(); |
|
| 52 |
faces[i].getMidPoint(midPoint); |
|
| 53 |
|
|
| 54 |
// Create Rectangle |
|
| 55 |
/* |
|
| 56 |
float poseX = faces[i].pose(Face.EULER_X); |
|
| 57 |
float poseY = faces[i].pose(Face.EULER_Y); |
|
| 58 |
float poseZ = faces[i].pose(Face.EULER_Z); |
|
| 59 |
|
|
| 60 |
Log.i(LOGTAG,"euclid: " + poseX + "," + poseY + "," + poseZ); |
|
| 61 |
*/ |
|
| 62 |
|
|
| 63 |
float widthBuffer = eyeDistance * 1.5f; |
|
| 64 |
float heightBuffer = eyeDistance * 2f; |
|
| 65 |
RectF faceRect = new RectF((midPoint.x-widthBuffer), |
|
| 66 |
(midPoint.y-heightBuffer), |
|
| 67 |
(midPoint.x+widthBuffer), |
|
| 68 |
(midPoint.y+heightBuffer)); |
|
| 69 |
|
|
| 70 |
DetectedFace dFace = new DetectedFace(); |
|
| 71 |
dFace.bounds = faceRect; |
|
| 72 |
dFace.midpoint = midPoint; |
|
| 73 |
dFace.eyeDistance = eyeDistance; |
|
| 74 |
|
|
| 75 |
dFaces.add(dFace); |
|
| 76 |
} |
|
| 77 |
} |
|
| 78 |
|
|
| 79 |
return dFaces; |
|
| 80 |
} |
|
| 81 |
|
|
| 82 |
} |
|
| app/src/main/java/org/witness/obscuracam/photo/detect/DetectedFace.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam.photo.detect; |
|
| 2 |
|
|
| 3 |
import android.graphics.PointF; |
|
| 4 |
import android.graphics.RectF; |
|
| 5 |
|
|
| 6 |
public class DetectedFace {
|
|
| 7 |
|
|
| 8 |
public RectF bounds; |
|
| 9 |
public PointF midpoint; |
|
| 10 |
public float eyeDistance; |
|
| 11 |
} |
|
| app/src/main/java/org/witness/obscuracam/photo/detect/FaceDetection.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam.photo.detect; |
|
| 2 |
|
|
| 3 |
import java.util.ArrayList; |
|
| 4 |
|
|
| 5 |
import android.graphics.Bitmap; |
|
| 6 |
|
|
| 7 |
public interface FaceDetection {
|
|
| 8 |
int findFaces(Bitmap bmp); // returns number of faces |
|
| 9 |
ArrayList<DetectedFace> getFaces(int numberFound); // returns array of rectangles of found faces |
|
| 10 |
void release (); |
|
| 11 |
} |
|
| app/src/main/java/org/witness/obscuracam/photo/filters/BlurObscure.java | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
* This ObscureMethod blurs the contents of the region |
|
| 3 |
*/ |
|
| 4 |
|
|
| 5 |
package org.witness.obscuracam.photo.filters; |
|
| 6 |
|
|
| 7 |
|
|
| 8 |
import java.util.Properties; |
|
| 9 |
|
|
| 10 |
import android.graphics.Bitmap; |
|
| 11 |
import android.graphics.Canvas; |
|
| 12 |
import android.graphics.Paint; |
|
| 13 |
import android.graphics.RectF; |
|
| 14 |
|
|
| 15 |
public class BlurObscure implements RegionProcesser {
|
|
| 16 |
|
|
| 17 |
Bitmap originalBmp; |
|
| 18 |
Properties mProps; |
|
| 19 |
Paint mPaint; |
|
| 20 |
|
|
| 21 |
private final static int BLUR_OFFSET = 10; |
|
| 22 |
|
|
| 23 |
public BlurObscure(Paint paint) {
|
|
| 24 |
mProps = new Properties (); |
|
| 25 |
mProps.put("obfuscationType", this.getClass().getName());
|
|
| 26 |
mPaint = paint; |
|
| 27 |
} |
|
| 28 |
|
|
| 29 |
public void processRegion(RectF rect, Canvas canvas, Bitmap bitmap) {
|
|
| 30 |
|
|
| 31 |
Bitmap bRect = applyGaussianBlur(bitmap, rect); |
|
| 32 |
|
|
| 33 |
canvas.drawBitmap(bRect, (int)rect.left, (int)rect.top, mPaint); |
|
| 34 |
|
|
| 35 |
// return properties and data as a map |
|
| 36 |
mProps.put("initialCoordinates", "[" + rect.top + "," + rect.left + "]");
|
|
| 37 |
mProps.put("regionWidth", Float.toString(Math.abs(rect.left - rect.right)));
|
|
| 38 |
mProps.put("regionHeight", Float.toString(Math.abs(rect.top - rect.bottom)));
|
|
| 39 |
|
|
| 40 |
} |
|
| 41 |
|
|
| 42 |
public static Bitmap applyGaussianBlur(Bitmap src, RectF rect) {
|
|
| 43 |
double[][] GaussianBlurConfig = new double[][] {
|
|
| 44 |
{ 1, 2, 1 },
|
|
| 45 |
{ 2, 4, 2 },
|
|
| 46 |
{ 1, 2, 1 }
|
|
| 47 |
}; |
|
| 48 |
ConvolutionMatrix convMatrix = new ConvolutionMatrix(3); |
|
| 49 |
convMatrix.applyConfig(GaussianBlurConfig); |
|
| 50 |
convMatrix.Factor = 16; |
|
| 51 |
convMatrix.Offset = 0; |
|
| 52 |
return ConvolutionMatrix.computeConvolution3x3(src, convMatrix, (int)rect.left,(int)rect.right,(int)rect.top,(int)rect.bottom); |
|
| 53 |
} |
|
| 54 |
|
|
| 55 |
/* |
|
| 56 |
private void makeItBlur(Rect rect) |
|
| 57 |
{
|
|
| 58 |
|
|
| 59 |
if (rect.left <= (0 + BLUR_OFFSET*2)) {
|
|
| 60 |
rect.left = (1 + BLUR_OFFSET*2); |
|
| 61 |
} else if (rect.right >= (originalBmp.getWidth()-1-BLUR_OFFSET*2)) {
|
|
| 62 |
rect.right = (originalBmp.getWidth() - 2 - BLUR_OFFSET*2); |
|
| 63 |
} |
|
| 64 |
|
|
| 65 |
if (rect.top <= (0 + BLUR_OFFSET*2)) {
|
|
| 66 |
rect.top = (1 + BLUR_OFFSET*2); |
|
| 67 |
} else if (rect.bottom >= (originalBmp.getHeight() - BLUR_OFFSET*2)) {
|
|
| 68 |
rect.bottom = (originalBmp.getHeight() - 2 - BLUR_OFFSET*2); |
|
| 69 |
} |
|
| 70 |
|
|
| 71 |
for (int x = rect.left; x < rect.right - 1; x++) {
|
|
| 72 |
for (int y = rect.top; y < rect.bottom - 1; y++) {
|
|
| 73 |
|
|
| 74 |
int blurOffset = (int)((Math.random()*BLUR_OFFSET)+BLUR_OFFSET); |
|
| 75 |
int r = getRed(x,y, blurOffset); |
|
| 76 |
|
|
| 77 |
blurOffset = (int)((Math.random()*BLUR_OFFSET)+BLUR_OFFSET); |
|
| 78 |
int g = getGreen(x,y, blurOffset); |
|
| 79 |
|
|
| 80 |
blurOffset = (int)((Math.random()*BLUR_OFFSET)+BLUR_OFFSET); |
|
| 81 |
int b = getBlue(x,y, blurOffset); |
|
| 82 |
|
|
| 83 |
originalBmp.setPixel(x, y, Color.rgb(r,g,b)); |
|
| 84 |
} |
|
| 85 |
} |
|
| 86 |
} |
|
| 87 |
|
|
| 88 |
|
|
| 89 |
private int getRed(int x, int y, int blurOffset) {
|
|
| 90 |
return |
|
| 91 |
(Color.red(originalBmp.getPixel(x-blurOffset, y-blurOffset)) + |
|
| 92 |
Color.red(originalBmp.getPixel(x, y-blurOffset)) + |
|
| 93 |
Color.red(originalBmp.getPixel(x+blurOffset, y-blurOffset)) + |
|
| 94 |
Color.red(originalBmp.getPixel(x-blurOffset, y)) + |
|
| 95 |
Color.red(originalBmp.getPixel(x, y)) + |
|
| 96 |
Color.red(originalBmp.getPixel(x+blurOffset, y)) + |
|
| 97 |
Color.red(originalBmp.getPixel(x-blurOffset, y+blurOffset)) + |
|
| 98 |
Color.red(originalBmp.getPixel(x, y+blurOffset)) + |
|
| 99 |
Color.red(originalBmp.getPixel(x+blurOffset, y+blurOffset)))/9; |
|
| 100 |
} |
|
| 101 |
|
|
| 102 |
private int getGreen(int x, int y, int blurOffset) {
|
|
| 103 |
return |
|
| 104 |
(Color.green(originalBmp.getPixel(x-blurOffset, y-blurOffset)) + |
|
| 105 |
Color.green(originalBmp.getPixel(x, y-blurOffset)) + |
|
| 106 |
Color.green(originalBmp.getPixel(x+blurOffset, y-blurOffset)) + |
|
| 107 |
Color.green(originalBmp.getPixel(x-blurOffset, y)) + |
|
| 108 |
Color.green(originalBmp.getPixel(x, y)) + |
|
| 109 |
Color.green(originalBmp.getPixel(x+blurOffset, y)) + |
|
| 110 |
Color.green(originalBmp.getPixel(x-blurOffset, y+blurOffset)) + |
|
| 111 |
Color.green(originalBmp.getPixel(x, y+blurOffset)) + |
|
| 112 |
Color.green(originalBmp.getPixel(x+blurOffset, y+blurOffset)))/9; |
|
| 113 |
} |
|
| 114 |
|
|
| 115 |
private int getBlue(int x, int y, int blurOffset) {
|
|
| 116 |
return |
|
| 117 |
(Color.blue(originalBmp.getPixel(x-blurOffset, y-blurOffset)) + |
|
| 118 |
Color.blue(originalBmp.getPixel(x, y-blurOffset)) + |
|
| 119 |
Color.blue(originalBmp.getPixel(x+blurOffset, y-blurOffset)) + |
|
| 120 |
Color.blue(originalBmp.getPixel(x-blurOffset, y)) + |
|
| 121 |
Color.blue(originalBmp.getPixel(x, y)) + |
|
| 122 |
Color.blue(originalBmp.getPixel(x+blurOffset, y)) + |
|
| 123 |
Color.blue(originalBmp.getPixel(x-blurOffset, y+blurOffset)) + |
|
| 124 |
Color.blue(originalBmp.getPixel(x, y+blurOffset)) + |
|
| 125 |
Color.blue(originalBmp.getPixel(x+blurOffset, y+blurOffset)))/9; |
|
| 126 |
}*/ |
|
| 127 |
|
|
| 128 |
public Properties getProperties() |
|
| 129 |
{
|
|
| 130 |
return mProps; |
|
| 131 |
} |
|
| 132 |
|
|
| 133 |
public void setProperties(Properties props) |
|
| 134 |
{
|
|
| 135 |
mProps = props; |
|
| 136 |
} |
|
| 137 |
|
|
| 138 |
@Override |
|
| 139 |
public Bitmap getBitmap() {
|
|
| 140 |
// TODO Auto-generated method stub |
|
| 141 |
return null; |
|
| 142 |
} |
|
| 143 |
|
|
| 144 |
} |
|
| 145 |
|
|
| 146 |
|
|
| 147 |
|
|
| app/src/main/java/org/witness/obscuracam/photo/filters/ConsentTagger.java | ||
|---|---|---|
| 1 |
package org.witness.obscuracam.photo.filters; |
|
| 2 |
|
|
| 3 |
import java.util.Properties; |
|
| 4 |
|
|
| 5 |
import android.graphics.Bitmap; |
|
| 6 |
import android.graphics.Canvas; |
|
| 7 |
import android.graphics.RectF; |
|
| 8 |
|
|
| 9 |
public class ConsentTagger implements RegionProcesser |
|
| 10 |
{
|
|
| 11 |
Properties mProps; |
|
| 12 |
private Bitmap mPreview; |
|
| 13 |
|
|
| 14 |
public ConsentTagger () |
|
| 15 |
{
|
|
| 16 |
mProps = new Properties (); |
|
| 17 |
mProps.put("regionSubject", "");
|
|
| 18 |
mProps.put("informedConsent", "false");
|
|
| 19 |
mProps.put("persistObscureType", "false");
|
|
| 20 |
mProps.put("obfuscationType", this.getClass().getName());
|
|
| 21 |
} |
|
| 22 |
|
|
| 23 |
@Override |
|
| 24 |
public void processRegion (RectF rect, Canvas canvas, Bitmap bitmap) |
|
| 25 |
{
|
|
| 26 |
// return properties and data as a map |
|
| 27 |
mProps.put("initialCoordinates", "[" + rect.top + "," + rect.left + "]");
|
|
| 28 |
mProps.put("regionWidth", Float.toString(Math.abs(rect.left - rect.right)));
|
|
| 29 |
mProps.put("regionHeight", Float.toString(Math.abs(rect.top - rect.bottom)));
|
|
| 30 |
mPreview = Bitmap.createBitmap( |
|
| 31 |
bitmap, |
|
| 32 |
(int) rect.left, |
|
| 33 |
(int) rect.top, |
|
| 34 |
(int) Math.min(bitmap.getWidth(),(Math.abs(rect.left - rect.right))), |
|
| 35 |
(int) Math.min(bitmap.getHeight(), (Math.abs(rect.top - rect.bottom))) |
|
| 36 |
); |
|
| 37 |
} |
|
| 38 |
|
|
| 39 |
public Properties getProperties() |
|
| 40 |
{
|
|
| 41 |
return mProps; |
|
| 42 |
} |
|
| 43 |
|
|
| 44 |
public void setProperties(Properties props) |
|
| 45 |
{
|
|
| 46 |
mProps = props; |
|
| 47 |
} |
|
| 48 |
|
|
| 49 |
@Override |
|
| 50 |
public Bitmap getBitmap() {
|
|
| 51 |
// TODO Auto-generated method stub |
|
| 52 |
return mPreview; |
|
| 53 |
} |
|
| 54 |
} |
|
| app/src/main/java/org/witness/obscuracam/photo/filters/ConvolutionMatrix.java | ||
|---|---|---|
| 1 |
|
|
| 2 |
/* |
|
| 3 |
* Many thanks to Pete Houston |
|
| 4 |
* http://xjaphx.wordpress.com/2011/06/22/image-processing-convolution-matrix/ |
|
| 5 |
*/ |
|
| 6 |
package org.witness.obscuracam.photo.filters; |
|
| 7 |
|
|
| 8 |
import android.graphics.Bitmap; |
|
| 9 |
import android.graphics.Color; |
|
| 10 |
|
|
| 11 |
|
|
| 12 |
public class ConvolutionMatrix |
|
| 13 |
{
|
|
| 14 |
public static final int SIZE = 3; |
|
| 15 |
|
|
| 16 |
public double[][] Matrix; |
|
| 17 |
public double Factor = 1; |
|
| 18 |
public double Offset = 1; |
|
| 19 |
|
|
| 20 |
public ConvolutionMatrix(int size) {
|
|
| 21 |
Matrix = new double[size][size]; |
|
| 22 |
} |
|
| 23 |
|
|
| 24 |
public void setAll(double value) {
|
|
| 25 |
for (int x = 0; x < SIZE; ++x) {
|
|
| 26 |
for (int y = 0; y < SIZE; ++y) {
|
|
| 27 |
Matrix[x][y] = value; |
|
| 28 |
} |
|
| 29 |
} |
|
| 30 |
} |
|
| 31 |
|
|
| 32 |
public void applyConfig(double[][] config) {
|
|
| 33 |
for(int x = 0; x < SIZE; ++x) {
|
|
| 34 |
for(int y = 0; y < SIZE; ++y) {
|
|
| 35 |
Matrix[x][y] = config[x][y]; |
|
| 36 |
} |
|
| 37 |
} |
|
| 38 |
} |
|
| 39 |
|
|
| 40 |
public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix, int left, int right, int top, int bottom) {
|
|
| 41 |
|
|
| 42 |
Bitmap result = Bitmap.createBitmap(right-left, bottom-top, src.getConfig()); |
|
| 43 |
|
|
| 44 |
int A, R, G, B; |
|
| 45 |
int sumR, sumG, sumB; |
|
| 46 |
int[][] pixels = new int[SIZE][SIZE]; |
|
| 47 |
|
|
| 48 |
for(int y = top; y < bottom - 2; ++y) {
|
|
| 49 |
for(int x = left; x < right - 2; ++x) {
|
|
| 50 |
|
|
| 51 |
// get pixel matrix |
|
| 52 |
for(int i = 0; i < SIZE; ++i) {
|
|
| 53 |
for(int j = 0; j < SIZE; ++j) {
|
|
| 54 |
pixels[i][j] = src.getPixel(x + i, y + j); |
|
| 55 |
} |
|
| 56 |
} |
|
| 57 |
|
|
| 58 |
// get alpha of center pixel |
|
| 59 |
A = Color.alpha(pixels[1][1]); |
|
| 60 |
|
|
| 61 |
// init color sum |
|
| 62 |
sumR = sumG = sumB = 0; |
|
| 63 |
|
|
| 64 |
// get sum of RGB on matrix |
|
| 65 |
for(int i = 0; i < SIZE; ++i) {
|
|
| 66 |
for(int j = 0; j < SIZE; ++j) {
|
|
| 67 |
sumR += (Color.red(pixels[i][j]) * matrix.Matrix[i][j]); |
|
| 68 |
sumG += (Color.green(pixels[i][j]) * matrix.Matrix[i][j]); |
|
| 69 |
sumB += (Color.blue(pixels[i][j]) * matrix.Matrix[i][j]); |
|
| 70 |
} |
|
| 71 |
} |
|
| 72 |
|
|
| 73 |
// get final Red |
|
| 74 |
R = (int)(sumR / matrix.Factor + matrix.Offset); |
|
| 75 |
if(R < 0) { R = 0; }
|
|
| 76 |
else if(R > 255) { R = 255; }
|
|
| 77 |
|
|
| 78 |
// get final Green |
|
| 79 |
G = (int)(sumG / matrix.Factor + matrix.Offset); |
|
| 80 |
if(G < 0) { G = 0; }
|
|
| 81 |
else if(G > 255) { G = 255; }
|
|
| 82 |
|
|
| 83 |
// get final Blue |
|
| 84 |
B = (int)(sumB / matrix.Factor + matrix.Offset); |
|
| 85 |
if(B < 0) { B = 0; }
|
|
| 86 |
else if(B > 255) { B = 255; }
|
|
| 87 |
|
|
| 88 |
// apply new pixel |
|
| 89 |
result.setPixel(x - left + 1, y - top + 1, Color.argb(A, R, G, B)); |
|
| 90 |
} |
|
| 91 |
} |
|
| 92 |
|
|
| 93 |
// final image |
|
| 94 |
return result; |
|
| 95 |
} |
|
| 96 |
} |
|
| app/src/main/java/org/witness/obscuracam/photo/filters/CrowdBlurObscure.java | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
* This ObscureMethod pixelizes the region |
|
| 3 |
*/ |
|
| 4 |
|
|
| 5 |
package org.witness.obscuracam.photo.filters; |
|
| 6 |
|
|
| 7 |
|
|
| 8 |
import java.util.Properties; |
|
| 9 |
|
|
| 10 |
import android.graphics.Bitmap; |
|
| 11 |
import android.graphics.Canvas; |
|
| 12 |
import android.graphics.RectF; |
|
| 13 |
|
|
| 14 |
public class CrowdBlurObscure implements RegionProcesser {
|
|
| 15 |
|
|
| 16 |
Bitmap originalBmp; |
|
| 17 |
Properties mProps; |
|
| 18 |
|
|
| 19 |
public static int PIXEL_BLOCK = 50; |
|
| 20 |
|
|
| 21 |
public CrowdBlurObscure() {
|
|
| 22 |
mProps = new Properties(); |
|
| 23 |
mProps.put("obfuscationType", this.getClass().getName());
|
|
| 24 |
} |
|
| 25 |
|
|
| 26 |
public void processRegion(RectF rect, Canvas canvas, Bitmap bitmap) {
|
|
| 27 |
|
|
| 28 |
originalBmp = bitmap; |
|
| 29 |
|
|
| 30 |
int pixelSize = originalBmp.getWidth()/PIXEL_BLOCK; |
|
| 31 |
|
|
| 32 |
if (pixelSize <= 0) //1 is the smallest it can be |
|
| 33 |
pixelSize = 1; |
|
| 34 |
|
|
| 35 |
pixelate(rect, pixelSize); |
|
| 36 |
|
|
| 37 |
// return properties and data as a map |
|
| 38 |
mProps.put("initialCoordinates", "[" + rect.top + "," + rect.left + "]");
|
|
| 39 |
mProps.put("regionWidth", Float.toString(Math.abs(rect.left - rect.right)));
|
|
| 40 |
mProps.put("regionHeight", Float.toString(Math.abs(rect.top - rect.bottom)));
|
|
| 41 |
|
|
| 42 |
} |
|
| 43 |
|
|
| 44 |
private void pixelate(RectF rect, int pixelSize) |
|
| 45 |
{
|
|
| 46 |
if (rect.left <= 0) {
|
|
| 47 |
rect.left = 1; |
|
| 48 |
} else if (rect.right >= originalBmp.getWidth()-1) {
|
|
| 49 |
rect.right = originalBmp.getWidth() - 1; |
|
| 50 |
} |
|
| 51 |
|
|
| 52 |
if (rect.top <= 0) {
|
|
| 53 |
rect.top = 1; |
|
| 54 |
} else if (rect.bottom >= originalBmp.getHeight()) {
|
|
| 55 |
rect.bottom = originalBmp.getHeight(); |
|
| 56 |
} |
|
| 57 |
|
|
| 58 |
int px, py; |
|
| 59 |
|
|
| 60 |
for (int x = 0; x < originalBmp.getWidth() - 1; x+=pixelSize) {
|
|
| 61 |
for (int y = 0; y < originalBmp.getHeight() - 1; y+=pixelSize) {
|
|
| 62 |
|
|
| 63 |
if (rect.contains(x, y)) |
|
| 64 |
continue; |
|
| 65 |
|
|
| 66 |
px = (x/pixelSize)*pixelSize; |
|
| 67 |
py = (y/pixelSize)*pixelSize; |
|
| 68 |
|
|
| 69 |
try |
|
| 70 |
{
|
|
| 71 |
//originalBmp.setPixel(x, y, originalBmp.getPixel(px,py)); |
|
| 72 |
|
|
| 73 |
int pixels[] = new int[pixelSize*pixelSize]; |
|
| 74 |
int newPixel = originalBmp.getPixel(px, py); |
|
| 75 |
for (int i = 0; i < pixels.length; i++) |
|
| 76 |
pixels[i] = newPixel; |
|
| 77 |
|
|
| 78 |
originalBmp.setPixels(pixels, 0, pixelSize, px, py, pixelSize, pixelSize); |
|
| 79 |
} |
|
| 80 |
catch (IllegalArgumentException iae) |
|
| 81 |
{
|
|
| 82 |
//something is wrong with our pixel math |
|
| 83 |
break; //stop the filter |
|
| 84 |
} |
|
| 85 |
} |
|
| 86 |
} |
|
| 87 |
} |
|
| 88 |
|
|
| 89 |
public Properties getProperties() |
|
| 90 |
{
|
|
| 91 |
return mProps; |
|
| 92 |
} |
|
| 93 |
|
|
| 94 |
public void setProperties(Properties props) |
|
| 95 |
{
|
|
| 96 |
mProps = props; |
|
| 97 |
} |
|
| 98 |
|
|
| 99 |
@Override |
|
| 100 |
public Bitmap getBitmap() {
|
|
| 101 |
// TODO Auto-generated method stub |
|
| 102 |
return null; |
|
| 103 |
} |
|
| 104 |
} |
|
| 105 |
|
|
| 106 |
|
|
| 107 |
|
|
| 108 |
|
|
| app/src/main/java/org/witness/obscuracam/photo/filters/CrowdPixelizeObscure.java | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
* This ObscureMethod pixelizes the region |
|
| 3 |
*/ |
|
| 4 |
|
|
| 5 |
package org.witness.obscuracam.photo.filters; |
|
| 6 |
|
|
| 7 |
|
|
| 8 |
import java.util.Properties; |
|
| 9 |
|
|
| 10 |
import android.graphics.Bitmap; |
|
| 11 |
import android.graphics.Canvas; |
|
| 12 |
import android.graphics.RectF; |
|
| 13 |
|
|
| 14 |
public class CrowdPixelizeObscure implements RegionProcesser {
|
|
| 15 |
|
|
| 16 |
Bitmap originalBmp; |
|
| 17 |
Properties mProps; |
|
| 18 |
|
|
| 19 |
public static int PIXEL_BLOCK = 50; |
|
| 20 |
|
|
| 21 |
public CrowdPixelizeObscure() {
|
|
Also available in: Unified diff