The thing is I want to write an app to capture audio and process it in the background with foreground service, start with a button on MainActivity and it's here.
I want to add the ability to take a screenshot, I've found this question, through which I found the example here.This template uses mediaproject to do it and whenever I press the icon to start it my MainActivity doesn't show up that the app will start running In the background, right.
Is there any other way to start screenshot from button on MainActivity(or how to continuous shooting screen),If possible I can completely capture the screen continuously.
PS:I searched but still don't know where to do it is probably because of using onActivityResult,
Here is the code that capture screen with mediaproject:
MainActivity.java
package com.commonsware.android.andshooter;
import android.app.Activity;
import android.content.Intent;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
public class MainActivity extends Activity {
private static final int REQUEST_SCREENSHOT=59706;
private MediaProjectionManager mgr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mgr=(MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
startActivityForResult(mgr.createScreenCaptureIntent(),
REQUEST_SCREENSHOT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==REQUEST_SCREENSHOT) {
if (resultCode==RESULT_OK) {
Intent i=
new Intent(this, ScreenshotService.class)
.putExtra(ScreenshotService.EXTRA_RESULT_CODE, resultCode)
.putExtra(ScreenshotService.EXTRA_RESULT_INTENT, data);
startService(i);
}
}
finish();
}
}
ImageTransmogrifier.java
package com.commonsware.android.andshooter;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.media.Image;
import android.media.ImageReader;
import android.view.Display;
import android.view.Surface;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
public class ImageTransmogrifier implements ImageReader.OnImageAvailableListener {
private final int width;
private final int height;
private final ImageReader imageReader;
private final ScreenshotService svc;
private Bitmap latestBitmap=null;
ImageTransmogrifier(ScreenshotService svc) {
this.svc=svc;
Display display=svc.getWindowManager().getDefaultDisplay();
Point size=new Point();
display.getRealSize(size);
int width=size.x;
int height=size.y;
while (width*height > (2<<19)) {
width=width>>1;
height=height>>1;
}
this.width=width;
this.height=height;
imageReader=ImageReader.newInstance(width, height,
PixelFormat.RGBA_8888, 2);
imageReader.setOnImageAvailableListener(this, svc.getHandler());
}
#Override
public void onImageAvailable(ImageReader reader) {
final Image image=imageReader.acquireLatestImage();
if (image!=null) {
Image.Plane[] planes=image.getPlanes();
ByteBuffer buffer=planes[0].getBuffer();
int pixelStride=planes[0].getPixelStride();
int rowStride=planes[0].getRowStride();
int rowPadding=rowStride - pixelStride * width;
int bitmapWidth=width + rowPadding / pixelStride;
if (latestBitmap == null ||
latestBitmap.getWidth() != bitmapWidth ||
latestBitmap.getHeight() != height) {
if (latestBitmap != null) {
latestBitmap.recycle();
}
latestBitmap=Bitmap.createBitmap(bitmapWidth,
height, Bitmap.Config.ARGB_8888);
}
latestBitmap.copyPixelsFromBuffer(buffer);
image.close();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
Bitmap cropped=Bitmap.createBitmap(latestBitmap, 0, 0,
width, height);
cropped.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] newPng=baos.toByteArray();
svc.processImage(newPng);
}
}
Surface getSurface() {
return(imageReader.getSurface());
}
int getWidth() {
return(width);
}
int getHeight() {
return(height);
}
void close() {
imageReader.close();
}
}
ScreenshotService.java
package com.commonsware.android.andshooter;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.ToneGenerator;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.WindowManager;
import java.io.File;
import java.io.FileOutputStream;
public class ScreenshotService extends Service {
private static final String CHANNEL_WHATEVER="channel_whatever";
private static final int NOTIFY_ID=9906;
static final String EXTRA_RESULT_CODE="resultCode";
static final String EXTRA_RESULT_INTENT="resultIntent";
static final String ACTION_RECORD=
BuildConfig.APPLICATION_ID+".RECORD";
static final String ACTION_SHUTDOWN=
BuildConfig.APPLICATION_ID+".SHUTDOWN";
static final int VIRT_DISPLAY_FLAGS=
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
private MediaProjection projection;
private VirtualDisplay vdisplay;
final private HandlerThread handlerThread=
new HandlerThread(getClass().getSimpleName(),
android.os.Process.THREAD_PRIORITY_BACKGROUND);
private Handler handler;
private MediaProjectionManager mgr;
private WindowManager wmgr;
private ImageTransmogrifier it;
private int resultCode;
private Intent resultData;
final private ToneGenerator beeper=
new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
#Override
public void onCreate() {
super.onCreate();
mgr=(MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
wmgr=(WindowManager)getSystemService(WINDOW_SERVICE);
handlerThread.start();
handler=new Handler(handlerThread.getLooper());
}
#Override
public int onStartCommand(Intent i, int flags, int startId) {
if (i.getAction()==null) {
resultCode=i.getIntExtra(EXTRA_RESULT_CODE, 1337);
resultData=i.getParcelableExtra(EXTRA_RESULT_INTENT);
foregroundify();
}
else if (ACTION_RECORD.equals(i.getAction())) {
if (resultData!=null) {
startCapture();
}
else {
Intent ui=
new Intent(this, MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(ui);
}
}
else if (ACTION_SHUTDOWN.equals(i.getAction())) {
beeper.startTone(ToneGenerator.TONE_PROP_NACK);
stopForeground(true);
stopSelf();
}
return(START_NOT_STICKY);
}
#Override
public void onDestroy() {
stopCapture();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
throw new IllegalStateException("Binding not supported. Go away.");
}
WindowManager getWindowManager() {
return(wmgr);
}
Handler getHandler() {
return(handler);
}
void processImage(final byte[] png) {
new Thread() {
#Override
public void run() {
File output=new File(getExternalFilesDir(null),
"screenshot.png");
try {
FileOutputStream fos=new FileOutputStream(output);
fos.write(png);
fos.flush();
fos.getFD().sync();
fos.close();
MediaScannerConnection.scanFile(ScreenshotService.this,
new String[] {output.getAbsolutePath()},
new String[] {"image/png"},
null);
}
catch (Exception e) {
Log.e(getClass().getSimpleName(), "Exception writing out screenshot", e);
}
}
}.start();
beeper.startTone(ToneGenerator.TONE_PROP_ACK);
stopCapture();
}
private void stopCapture() {
if (projection!=null) {
projection.stop();
vdisplay.release();
projection=null;
}
}
private void startCapture() {
projection=mgr.getMediaProjection(resultCode, resultData);
it=new ImageTransmogrifier(this);
MediaProjection.Callback cb=new MediaProjection.Callback() {
#Override
public void onStop() {
vdisplay.release();
}
};
vdisplay=projection.createVirtualDisplay("andshooter",
it.getWidth(), it.getHeight(),
getResources().getDisplayMetrics().densityDpi,
VIRT_DISPLAY_FLAGS, it.getSurface(), null, handler);
projection.registerCallback(cb, handler);
}
private void foregroundify() {
NotificationManager mgr=
(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O &&
mgr.getNotificationChannel(CHANNEL_WHATEVER)==null) {
mgr.createNotificationChannel(new NotificationChannel(CHANNEL_WHATEVER,
"Whatever", NotificationManager.IMPORTANCE_DEFAULT));
}
NotificationCompat.Builder b=
new NotificationCompat.Builder(this, CHANNEL_WHATEVER);
b.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL);
b.setContentTitle(getString(R.string.app_name))
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(getString(R.string.app_name));
b.addAction(R.drawable.ic_record_white_24dp,
getString(R.string.notify_record),
buildPendingIntent(ACTION_RECORD));
b.addAction(R.drawable.ic_eject_white_24dp,
getString(R.string.notify_shutdown),
buildPendingIntent(ACTION_SHUTDOWN));
startForeground(NOTIFY_ID, b.build());
}
private PendingIntent buildPendingIntent(String action) {
Intent i=new Intent(this, getClass());
i.setAction(action);
return(PendingIntent.getService(this, 0, i, 0));
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.commonsware.android.andshooter"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name">
<activity
android:name=".MainActivity"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ScreenshotService"
android:exported="true" />
</application>
</manifest>
In my application I simply copy the ScreenshotService ImageTransmogrifier file then run it from MainActivity as above.
Related
Please Share code in answers if possible
Here is My code, basically I think my app is not responding after sometime maybe because the freezing gui and high memory usage, It is using even 16.8 MB of memory while in background. Please share some tips by which I can make my app simple and fast without losing functionality.
StopWatch.java
package com.study.meter;
import android.app.Service;
import android.os.IBinder;
import android.content.Intent;
import android.widget.Toast;
import android.os.Handler;
import java.util.Locale;
import android.app.PendingIntent;
import androidx.core.app.NotificationCompat;
import android.app.NotificationManager;
import android.app.Notification;
import android.content.Context;
public class StopWatch extends Service{
public static StopWatch getStopWatch;
public static int StopWatchSecs;
public static boolean isStopWatchRunning = false;
public static boolean isRunning;
public String StopWatchTime;
private NotificationCompat.Builder builder;
private Intent notificationIntent;
private PendingIntent contentIntent;
private Notification notificaton;
private NotificationManager manager;
private String StopWatchNotificationText,StopWatchNotificationTitle;
#Override
public int onStartCommand (Intent intent, int flags, int startId)
{
return START_CONTINUATION_MASK;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
getStopWatch = this;
}
#Override
public void onDestroy() {
isRunning = false;
Toast.makeText(getBaseContext(),"Destroyed",Toast.LENGTH_SHORT).show();
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startid) {
super.onStart(intent,startid);
isRunning = true;
}
public Handler StopWatchHandler = new Handler();
public Runnable StopWatchRunnable = new Runnable()
{
#Override
public void run()
{
StopWatchSecs++;
int seconds = StopWatchSecs;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
int secs = seconds % 60;
// Format the seconds into hours, minutes,
// and seconds.
StopWatchTime
= String
.format(Locale.getDefault(),
"%d:%02d:%02d", hours,
minutes, secs);
// if app is running then change counting
if(MainActivity.Stop_Watch!=null && MainActivity.isAppRunning)
{
// Set the text view text.
MainActivity.Stop_Watch.setText(StopWatchTime);
}
addStopWatchNotification("StopWatch",StopWatchTime);
StopWatchHandler.postDelayed(StopWatchRunnable,1000);
}
};
public void Start_Watch()
{
StopWatchHandler.post(StopWatchRunnable);
}
public void Stop_Watch()
{
StopWatchHandler.removeCallbacks(StopWatchRunnable);
}
public String Start_Or_Stop_Watch()
{
String result = "Start";
if(isStopWatchRunning)
{
result = "Resume";
isStopWatchRunning = false;
Stop_Watch();
}
else if(!isStopWatchRunning)
{
result = "Pause";
isStopWatchRunning = true;
Start_Watch();
}
return result;
}
// adding new Handler for notifications to not overload memory
public Handler StopWatchNotificationHandler = new Handler();
public Runnable StopWatchNotificationRunnable;
public void addStopWatchNotification(String title,String text)
{
if(builder==null)
{
builder = new NotificationCompat.Builder(this);
builder
.setSmallIcon(R.drawable.notify_icon)
.setAutoCancel(false)
.setOnlyAlertOnce(true);
}
if(notificationIntent==null)
{
notificationIntent = new Intent(this, MainActivity.class);
}
if(contentIntent==null)
{
contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
}
if(manager==null)
{
manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
if(StopWatchNotificationRunnable==null)
{
StopWatchNotificationRunnable = new Runnable()
{
#Override
public void run()
{
builder
.setContentTitle(title)
.setContentText(text);
notificaton = builder.build();
notificaton.flags |= Notification.FLAG_NO_CLEAR;
manager.notify(0, notificaton);
}
};
}
StopWatchNotificationText = text;
StopWatchNotificationTitle = title;
StopWatchNotificationHandler.post(StopWatchNotificationRunnable);
}
}
MainActivity.java
package com.study.meter;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.content.Context;
public class MainActivity extends AppCompatActivity
{
public static boolean isAppRunning;
public static TextView Stop_Watch;
public static MainActivity activity;
public Button Start_Watch;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// set content view
setContentView(R.layout.activity_main);
// hide statusbar
getSupportActionBar().hide();
activity = this;
// set the value of StopWatch
Stop_Watch = findViewById(R.id.StopWatch);
Start_Watch = findViewById(R.id.StartWatch);
//if StopWatch service is not running
if(!StopWatch.isRunning)
{
// start the service
startService(new Intent(this, StopWatch.class));
}
}
#Override
public void onResume()
{
super.onResume();
isAppRunning = true;
if(StopWatch.StopWatchSecs!=0)
{
// if stopwatchsecs is not equal to null or 0
if(StopWatch.isStopWatchRunning)
{
// if stopwatch is running in background
Start_Watch.setText("Pause");
}else
{
// if stopwatch is not running in background
Start_Watch.setText("Resume");
}
}
}
#Override
public void onPause()
{
isAppRunning = false;
super.onPause();
}
// "StartWatch" click
public void StartorStop(View v)
{
Button sv = (Button)v;
String StartWatchText = StopWatch.getStopWatch.Start_Or_Stop_Watch();
sv.setText(StartWatchText);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.study.meter"
android:installLocation="auto">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.StudyMeter">
<service
android:name=".StopWatch"
android:stopWithTask="false"/>
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|screenLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/StopWatch"
android:textSize="65dp"
android:text="0:00:00"
app:layout_constraintBottom_toTopOf="#id/StartWatch"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:layout_height="50dp"
android:layout_width="wrap_content"
android:id="#+id/StartWatch"
android:text="Start"
android:onClick="StartorStop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/StopWatch"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Seems like an architecture problem, try to modulate more your Java code by dividing it in more activities, too much tasks in few activities causes crashes and poor performance ;)
In my App's MainActivity I am playing some sounds using MediaPlayers and in The onPause() in that activity I realease the players and I am starting a service to continue playing these sounds by creating them again and I send the resourcesNames and the Volume of every player from the activity to the service , I am using setLooping() to make these sounds loop and I am running the service in a new thread (outside the main thread) uding Handler and HandlerThread.
when the activity gets paused the service starts and the sounds are playing but the problem is that they just loop for 3 times and then the service is getting destroyed without stopService() or stopSelf() are being called and also without exiting from the app(the app still in the recent apps)?
Here the sevice's code :
package com.example.naturesounds;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.util.Log;
import androidx.annotation.NonNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
public class SoundSPlayingService extends Service implements MediaPlayer.OnPreparedListener
{
private static final String PACKAGE_NAME = "com.example.naturesounds";
private float playerVolume = 0.0f;
serviceHandler serviceHandler;
Looper serviceLooper;
HandlerThread thread;
Intent intent;
Bundle playersVolume = new Bundle() ;
ArrayList<String> runningResourceNames = new ArrayList<>();
HashMap<String, MediaPlayer> playersMap = new HashMap<>();
#Override
public void onCreate() {
thread = new HandlerThread("ServiceThread", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
serviceLooper = thread.getLooper();
serviceHandler = new serviceHandler(serviceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message message = serviceHandler.obtainMessage();
message.obj = intent;
serviceHandler.sendMessage(message);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onDestroy() {
releasePlayers();
Log.d("serviceLifeCycle","onDestroy() is running");
}
public void createPlayer(String resourceName)
{
playersMap.put(resourceName,new MediaPlayer());
try {
playersMap.get(resourceName).setDataSource(getApplicationContext(),
Uri.parse("android.resource://com.example.naturesounds/raw/" + resourceName));
playersMap.get(resourceName).setOnPreparedListener(this);
playersMap.get(resourceName).prepareAsync();
playersMap.get(resourceName).setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
setPlayerLooping(resourceName);
setPlayerVolume(resourceName);
}
catch (IOException e1)
{
e1.printStackTrace();
}
catch (IllegalArgumentException e2)
{
e2.printStackTrace();
}
}
public void releasePlayers()
{
for(int i=0 ; i<runningResourceNames.size(); i++)
{
String resourceName = runningResourceNames.get(i);
if(playersMap.get(resourceName) != null)
{
playersMap.get(resourceName).release();
playersMap.put(resourceName,null);
}
}
}
public void setPlayerVolume(String resourceName)
{
playerVolume = playersVolume.getFloat(resourceName);
Log.d("playerVolume",String.valueOf(playerVolume));
playersMap.get(resourceName).setVolume(playerVolume,playerVolume);
}
public void setPlayerLooping(String resourceName)
{
playersMap.get(resourceName).setLooping(true);
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
class serviceHandler extends Handler
{
public serviceHandler(Looper looper)
{
super(looper);
}
#Override
public void handleMessage(#NonNull Message msg) {
Log.d("serviceHandlerChecking","handleMessage() is executing");
intent = (Intent) msg.obj;
runningResourceNames = intent.getStringArrayListExtra(PACKAGE_NAME + ".MainActivity.runningResourceNames");
playersVolume = intent.getBundleExtra(PACKAGE_NAME + ".MainActivity.playersVolume");
for(int i=0; i<runningResourceNames.size(); i++)
{
String resourceName = runningResourceNames.get(i);
createPlayer(resourceName);
}
}
}
}
I followed this tutorial : https://developer.android.com/training/camera/photobasics .
I had some errors, but I resolved them and the app was working fine.
Once you took a picture, the picture would be saved in under this path :
Android/data/<YourAppPackageName>/files/Pictures.
However, after last OS update I'm getting an empty image file with size 0 B!
How can I solve this issue?
here is my github project : https://github.com/AlineJo/CameraGalleryImage.git
here is my code :
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cameragalleryimage">
<!--Permission to write to storage-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--Inform google play that your app can take pictures-->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<!-- File provider is a generic way to store image file across different Android SDK, And it enable us to get uri-->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.cameragalleryimage.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/img_file_path"></meta-data>
</provider>
<activity android:name=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
UploadImageFragment
package com.example.cameragalleryimage.fragments;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
import com.example.cameragalleryimage.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import static android.app.Activity.RESULT_OK;
/**
* A simple {#link Fragment} subclass.
*/
public class UploadImageFragment extends Fragment implements ChooseDialogFragment.ChooseDialogInterface {
private static final int PICK_IMAGE = 100;
private static final int CAPTURE_IMAGE = 200;
private static final int STORAGE_PERMISSION_REQUEST = 300;
private Context mContext;
private Uri mImageUri;
private ImageView ivImg;
private TextView tvProgress;
private ProgressBar progressBar;
private String mImagePath;
public UploadImageFragment() {
// Required empty public constructor
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View parentView = inflater.inflate(R.layout.fragment_upload_image, container, false);
ivImg = parentView.findViewById(R.id.iv_img);
tvProgress = parentView.findViewById(R.id.tv_progress);
progressBar = parentView.findViewById(R.id.progressBar);
Button btnChoose = parentView.findViewById(R.id.btn_choose);
Button btnUpload = parentView.findViewById(R.id.btn_upload);
btnChoose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChooseDialogFragment dialog = new ChooseDialogFragment();
dialog.setChooseDialogListener(UploadImageFragment.this);
dialog.show(getChildFragmentManager(), ChooseDialogFragment.class.getSimpleName());
}
});
btnUpload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mImageUri == null) {
Toast.makeText(mContext, "Please take an image", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "Image URI Found : " + mImageUri.toString(), Toast.LENGTH_LONG).show();
}
}
});
return parentView;
}
#Override
public void onGalleryButtonClick() {
Intent i = new Intent();
i.setType("image/*"); // specify the type of data you expect
i.setAction(Intent.ACTION_GET_CONTENT); // we need to get content from another act.
startActivityForResult(Intent.createChooser(i, "choose App"), PICK_IMAGE);
}
#Override
public void onCameraButtonClick() {
if (isPermissionGranted()) {
openCamera();
} else {
showRunTimePermission();
}
}
private void openCamera() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.d("capture_error", ex.toString());
}
// Continue only if the File was successfully created
if (photoFile != null) {
mImageUri = FileProvider.getUriForFile(mContext,
"com.example.cameragalleryimage.fileprovider",
photoFile);
startActivityForResult(takePictureIntent, CAPTURE_IMAGE);
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
if (requestCode == CAPTURE_IMAGE) {//img from camera
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ivImg.setImageBitmap(imageBitmap);
} else if (requestCode == PICK_IMAGE) {// img from gallery
try {
Uri imgUri = data.getData();
InputStream imageStream = mContext.getContentResolver().openInputStream(imgUri);//2
Bitmap selectedImageBitmap = BitmapFactory.decodeStream(imageStream);//3}
mImageUri = imgUri;
ivImg.setImageBitmap(selectedImageBitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
} else {
Toast.makeText(mContext, "Unexpected Error Happened while selecting picture!", Toast.LENGTH_SHORT).show();
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp + "_";
File storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);// mContext.getExternalCacheDir();
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mImagePath = image.getAbsolutePath();
return image;
}
private boolean isPermissionGranted() {
return ActivityCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public void showRunTimePermission() {
// Permission is not Granted !
// we should Request the Permission!
// put all permissions you need in this Screen into string array
String[] permissionsArray = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
//here we requet the permission
requestPermissions(permissionsArray, STORAGE_PERMISSION_REQUEST);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// user grants the Permission!
// you can call the function to write/read to storage here!
openCamera();
} else {
// user didn't grant the Permission we need
Toast.makeText(mContext, "Please Grant the Permission To use this Feature!", Toast.LENGTH_LONG).show();
}
}
}
img_file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path
name="my_images"
path="/" />
<!-- Android/data/com.example.cameragalleryimage/files/Pictures-->
</paths>
Super thanks to #CommonsWare and #blackapps comments I was able to get uri and display the captured image
You can find the updated GitHub project here: https://github.com/AlineJo/CameraGalleryImage.git
here is the code I changed :
package com.example.cameragalleryimage.fragments;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.example.cameragalleryimage.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import static android.app.Activity.RESULT_OK;
/**
* A simple {#link Fragment} subclass.
*/
public class UploadImageFragment extends Fragment implements ChooseDialogFragment.ChooseDialogInterface {
private static final int PICK_IMAGE = 100;
private static final int CAPTURE_IMAGE = 200;
private static final int STORAGE_PERMISSION_REQUEST = 300;
private Context mContext;
private Uri mImageUri;
private ImageView ivImg;
private TextView tvProgress;
private ProgressBar progressBar;
private String mImagePath;
private File photoFile;
public UploadImageFragment() {
// Required empty public constructor
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View parentView = inflater.inflate(R.layout.fragment_upload_image, container, false);
ivImg = parentView.findViewById(R.id.iv_img);
tvProgress = parentView.findViewById(R.id.tv_progress);
progressBar = parentView.findViewById(R.id.progressBar);
Button btnChoose = parentView.findViewById(R.id.btn_choose);
Button btnUpload = parentView.findViewById(R.id.btn_upload);
btnChoose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChooseDialogFragment dialog = new ChooseDialogFragment();
dialog.setChooseDialogListener(UploadImageFragment.this);
dialog.show(getChildFragmentManager(), ChooseDialogFragment.class.getSimpleName());
}
});
btnUpload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mImageUri == null) {
Toast.makeText(mContext, "Please take an image", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(mContext, "Image URI Found : " + mImageUri.toString(), Toast.LENGTH_LONG).show();
}
}
});
return parentView;
}
#Override
public void onGalleryButtonClick() {
Intent i = new Intent();
i.setType("image/*"); // specify the type of data you expect
i.setAction(Intent.ACTION_GET_CONTENT); // we need to get content from another act.
startActivityForResult(Intent.createChooser(i, "choose App"), PICK_IMAGE);
}
#Override
public void onCameraButtonClick() {
if (isPermissionGranted()) {
openCamera();
} else {
showRunTimePermission();
}
}
private void openCamera() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
// Create the File where the photo should go
photoFile = null;
try {
photoFile = createFileInstance();
} catch (IOException ex) {
// Error occurred while creating the File
Log.d("capture_error", ex.toString());
}
// Continue only if the File was successfully created
if (photoFile != null) {
mImageUri = FileProvider.getUriForFile(mContext,
"com.example.cameragalleryimage.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri); //this code was messing, However adding this code will make "Intent data" (in "onActivityResult") to be null
Glide.with(mContext).load(mImageUri).into(ivImg);//solution ask glide to load the image using uri
startActivityForResult(takePictureIntent, CAPTURE_IMAGE);
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
if (requestCode == PICK_IMAGE) {// img from gallery
try {
Uri imgUri = data.getData();
InputStream imageStream = mContext.getContentResolver().openInputStream(imgUri);//2
Bitmap selectedImageBitmap = BitmapFactory.decodeStream(imageStream);//3}
mImageUri = imgUri;
ivImg.setImageBitmap(selectedImageBitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
} else {
if (requestCode == CAPTURE_IMAGE) {
if (photoFile.length() == 0) {
Toast.makeText(mContext, "You took an image, but you canceled it!", Toast.LENGTH_SHORT).show();
mImageUri = null;
}
}
}
}
private File createFileInstance() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp + "_";
File storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);// mContext.getExternalCacheDir();
File image = new File(storageDir.toString()+"/"+imageFileName+".png");
// Save a file: path for use with ACTION_VIEW intents
mImagePath = image.getAbsolutePath();
return image;
}
private boolean isPermissionGranted() {
return ActivityCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public void showRunTimePermission() {
// Permission is not Granted !
// we should Request the Permission!
// put all permissions you need in this Screen into string array
String[] permissionsArray = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
//here we requet the permission
requestPermissions(permissionsArray, STORAGE_PERMISSION_REQUEST);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// user grants the Permission!
// you can call the function to write/read to storage here!
openCamera();
} else {
// user didn't grant the Permission we need
Toast.makeText(mContext, "Please Grant the Permission To use this Feature!", Toast.LENGTH_LONG).show();
}
}
}
If you are updated to Android10. Then use below code snippet.
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
Working on an app that is supposed to generate random characters via a broadcast. I need to broadcast the random characters generated by my custom service, so that the main activity registered to intercept the broadcast can get the random numbers and display them on an EditText. The layout is shown here: app layout
The start button will trigger the random character generator service. The EditText will display the random numbers generated in real time (without any button press). The stop button will stop the service. The EditText won’t display any numbers. I have created a service(RandomCharacterService) and registered it in my manifest. Upon running the app, my app crashes. I am sure it is because I did not register my broadcast in my manifest, but I do not understand how to do that. And perhaps there is something wrong with how I am handling the broadcast in my main activity. In my button click method for the start button, I tried to do a for-loop, but this resulted in the app crashing as well.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cs7455rehmarazzaklab8">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".RandomCharacterService"></service>
</application>
MainActivityjava:
package com.example.cs7455rehmarazzaklab8;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.support.constraint.ConstraintLayout;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;
import java.util.Random;
public class MainActivity extends AppCompatActivity
{
private Button btnStart, btnStop;
private EditText myTV;
private Intent serviceIntent;
private RandomCharacterService myService;
private ServiceConnection myServiceConnection;
private boolean isServiceOn; //checks if the service is on
private int myRandomCharacter;
char MyRandomCharacter = (char)myRandomCharacter;
private boolean isRandomGeneratorOn;
private final int MIN = 65;
char m = (char)MIN;
private final int MAX = 26;
char x = (char)MAX;
private final String TAG = "Random Char Service: ";
private final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Context mContext;
private Random mRandom = new Random();
// Initialize a new BroadcastReceiver instance
private BroadcastReceiver mRandomCharReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent) {
// Get the received random number
myRandomCharacter = intent.getIntExtra("RandomCharacter",-1);
// Display a notification that the broadcast received
Toast.makeText(context,"Received : " + myRandomCharacter,Toast.LENGTH_SHORT).show();
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_ACTION_BAR);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get the application context
mContext = getApplicationContext();
btnStart = (Button) findViewById(R.id.StartButton);
btnStop = (Button) findViewById(R.id.StopButton);
myTV = (EditText)findViewById(R.id.RandomCharText);
// Register the local broadcast
LocalBroadcastManager.getInstance(mContext).registerReceiver(mRandomCharReceiver, new IntentFilter("BROADCAST_RANDOM_CHARACTER"));
// Change the action bar color
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#FFFF00BF")));
// Set a click listener for start button
btnStart.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
isServiceOn = true;
serviceIntent = new Intent(getApplicationContext(), RandomCharacterService.class);
startService(serviceIntent);
setRandomNumber();
// Generate a random char
myRandomCharacter = new Random().nextInt(x)+m;
// Initialize a new intent instance
Intent intent = new Intent("BROADCAST_RANDOM_CHARACTER");
// Put the random character to intent to broadcast it
intent.putExtra("RandomCharacter",myRandomCharacter);
// Send the broadcast
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
// Update the TextView with random character
myTV.setText(" " + myRandomCharacter );
}
});
btnStop.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
isServiceOn = false;
stopService(serviceIntent);
}
});
}
private void setRandomNumber()
{
myTV.setText("Random Character: " + (char)myService.getRandomCharacter());
String alphabet = myTV.getText().toString();
}
}
RandomCharacterService.java:
package com.example.cs7455rehmarazzaklab8;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.Random;
public class RandomCharacterService extends Service
{
private int myRandomCharacter;
char MyRandomCharacter = (char)myRandomCharacter;
private boolean isRandomGeneratorOn;
private final int MIN = 65;
char m = (char)MIN;
private final int MAX = 26;
char x = (char)MAX;
private final String TAG = "Random Char Service: ";
private final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
class RandomCharacterServiceBinder extends Binder{
public RandomCharacterService getService()
{
return RandomCharacterService.this;
}
}
private IBinder myBinder = new RandomCharacterServiceBinder();
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.i(TAG, "In OnStartCommand Thread ID is "+Thread.currentThread().getId());
isRandomGeneratorOn = true;
new Thread(new Runnable()
{
#Override
public void run()
{
startRandomGenerator();
}
}
).start();
return START_STICKY;
}
private void startRandomGenerator()
{
while(isRandomGeneratorOn)
{
char alphabet = 'A';
for (int i = 65; i < 90; i++)
{
try
{
Thread.sleep(1000);
if(isRandomGeneratorOn)
{
alphabet++;
myRandomCharacter = new Random().nextInt(x)+m;
Log.i(TAG, "Thread ID is "+Thread.currentThread().getId() + ", Random character is "+(char)myRandomCharacter);
}
}
catch(InterruptedException e)
{
Log.i(TAG, "Thread Interrupted.");
}
}
}
}
private void stopRandomGenerator()
{
isRandomGeneratorOn = false;
}
public int getRandomCharacter()
{
return myRandomCharacter;
}
public boolean isRandomGeneratorOn() {
return isRandomGeneratorOn;
}
#Override
public void onDestroy()
{
super.onDestroy();
stopRandomGenerator();
Log.i(TAG, "Service Destroyed.");
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
Log.i(TAG, "In onBind ...");
return myBinder;
}
}
Call Stack:callstack from running the app
Call Stack from attempting to press the stop button:crash from attempting to press stop button
Since you are using the bound service (using Ibinder). You will have to start the service by calling bindService instead of startService. But before that you need to initialize your ServiceConnection variable and better use the isServiceOn boolean as in the below example.
private ServiceConnection myServiceConnection = new ServiceConnection() {
#Override
// IBinder interface is through which we receive the service object for communication.
public void onServiceConnected(ComponentName name, IBinder binder) {
RandomCharacterServiceBinder myBinder = (RandomCharacterServiceBinder) binder;
isServiceOn = true;
myService = myBinder.getService();
Toast.makeText(context,"Service connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onServiceDisconnected(ComponentName name) {
isServiceOn = false;
myService = null;
}
};
After onServiceConnected is called, you will get your service object. Most probably your service will be initialized before you perform a click. But just to ensure you can TOAST some message within it.
And you should start the service in Activity's onCreate method, so service will get some time in creation. So move the below code from you click listener to onCreate method.
serviceIntent = new Intent(getApplicationContext(), RandomCharacterService.class);
// startService(serviceIntent); <-- remove this line, call bindService
bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
and wait for the service connection Toast to appear.
I am working on an android app and am trying to figure out how to get a popup confirmation window to display with confirm and cancel buttons when a button is pressed.
Here is the creation of the alert.
final AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity);
alertBuilder.setTitle("Your Title");
alertBuilder.setMessage("Your Messages");
alertBuilder.setPositiveButton("Confirm", new OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do something with value!
}
});
alertBuilder.setNegativeButton("Cancel", new OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
Here is the call to show.
Sprite p2 = new Sprite(goldMult, 25, 450, WIDTH, HEIGHT,
resourceManager.spriteRegion, vbom) {
/**
* #see org.andengine.entity.shape.Shape#onAreaTouched(org.andengine.input.touch.TouchEvent, float, float)
*/
#Override
public boolean onAreaTouched(final TouchEvent sceneTouchEvent, final float touchAreaLocalX,
final float touchAreaLocalY) {
AlertDialog alert = alertBuilder.create();
alert.show();
I am getting this exception:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I saw a post with a similar issue here
However I am confused on how to implement this with my onAreaClicked event.
Thanks for any help in advanced
andengine uses opengl so you might want to create a handler to execute your dialog on the opengl thread
public Handler handler;
then
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
AlertDialog alert = alertBuilder.create();
alert.show();
break;
}
}};
then to use it
handler.sendMessage(Message.obtain(handler, 0));
something along those lines
EDIT: class using handler for looper prepare opengl
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.IntBuffer;
import java.util.List;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.AsyncFacebookRunner.RequestListener;
import com.facebook.android.DialogError;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;
import com.facebook.android.Facebook.DialogListener;
import pic.puzzle.framework.Audio;
import pic.puzzle.framework.FileIO;
import pic.puzzle.framework.Game;
import pic.puzzle.framework.Graphics;
import pic.puzzle.framework.Input;
import pic.puzzle.framework.Screen;
import pic.puzzle.picturepuzzle.GameOverScreen;
import pic.puzzle.picturepuzzle.GameOverScreenCustom;
import pic.puzzle.picturepuzzle.PicturePuzzleScreen;
import pic.puzzle.picturepuzzle.PuzzleScreen;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.net.Uri;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public abstract class GLGame extends Activity implements Game, Renderer {
enum GLGameState {
Initialized,
Running,
Paused,
Finished,
Idle
}
GLSurfaceView glView;
GLGraphics glGraphics;
Audio audio;
Input input;
FileIO fileIO;
Screen screen;
GLGameState state = GLGameState.Initialized;
Object stateChanged = new Object();
long startTime = System.nanoTime();
WakeLock wakeLock;
public static Bitmap lastscreenshot;
public static boolean screenshot = false,finish = false;
public static int width, height;
public static Handler handler;
public static boolean share = false;
String APP_ID = ("567944629883125");
public Facebook fb;
public byte[] data;
public static int custom = 0;
public Uri uri;
String here;
#SuppressLint("HandlerLeak")
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
glView = new GLSurfaceView(this);
glView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);
glView.setRenderer(this);
setContentView(glView);
fb = new Facebook(APP_ID);
glGraphics = new GLGraphics(glView);
fileIO = new AndroidFileIO(getAssets());
audio = new AndroidAudio(this);
input = new AndroidInput(this, glView, 1, 1);
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GLGame");
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
if(custom == 0)
uri = GameOverScreen.pngUri;
else if(custom == 1)
uri = GameOverScreenCustom.pngUri;
if(custom == 0){
here = "Moves: " + GameOverScreen.moves + " " + "Time: " + GameOverScreen.time;}
else if(custom == 1){
here = "Moves: " + GameOverScreenCustom.moves + " " + "Time: " + GameOverScreenCustom.time;}
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT,
here);
shareIntent.setType("image/png");
shareIntent.putExtra(android.content.Intent.EXTRA_STREAM,
uri); //Share the image on Facebook
PackageManager pm = getApplicationContext().getPackageManager();
List<ResolveInfo> activityList = pm.queryIntentActivities(
shareIntent, 0);
for (final ResolveInfo app : activityList) {
if ((app.activityInfo.name).contains("facebook")) {
final ActivityInfo activity = app.activityInfo;
final ComponentName name = new ComponentName(
activity.applicationInfo.packageName,
activity.name);
shareIntent.addCategory(Intent.CATEGORY_LAUNCHER);
shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
shareIntent.setComponent(name);
startActivity(shareIntent);
break;
}
}
}
}
};
}
public void onResume() {
super.onResume();
glView.onResume();
wakeLock.acquire();
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glGraphics.setGL(gl);
synchronized(stateChanged) {
if(state == GLGameState.Initialized)
screen = getStartScreen();
state = GLGameState.Running;
screen.resume();
startTime = System.nanoTime();
}
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLGame.width = width;
GLGame.height = height;
}
#Override
public void onDrawFrame(GL10 gl) {
GLGameState state = null;
if(finish){
finish = false;
finish();
}
if(share) {
share = false;
handler.sendMessage(Message.obtain(handler, 0));
}
synchronized(stateChanged) {
state = this.state;
}
if(state == GLGameState.Running) {
float deltaTime = (System.nanoTime()-startTime) / 1000000000.0f;
startTime = System.nanoTime();
screen.update(deltaTime);
screen.present(deltaTime);
if(screenshot){
lastscreenshot = SavePixels(0,0,width,height,gl);
lastscreenshot = Bitmap.createScaledBitmap(lastscreenshot, 320, 480, true);
screenshot = false;
}
}
if(state == GLGameState.Paused) {
screen.pause();
synchronized(stateChanged) {
this.state = GLGameState.Idle;
stateChanged.notifyAll();
}
}
if(state == GLGameState.Finished) {
screen.pause();
screen.dispose();
synchronized(stateChanged) {
this.state = GLGameState.Idle;
stateChanged.notifyAll();
}
}
}
#Override
public void onPause() {
synchronized(stateChanged) {
if(isFinishing())
state = GLGameState.Finished;
else
state = GLGameState.Paused;
while(true) {
try {
stateChanged.wait();
break;
} catch(InterruptedException e) {
}
}
}
wakeLock.release();
glView.onPause();
super.onPause();
}
#Override
public void onDestroy(){
if(lastscreenshot != null)
lastscreenshot.recycle();
if(PicturePuzzleScreen.pic != null)
PicturePuzzleScreen.pic.recycle();
if(GameOverScreen.finalbitmap != null)
GameOverScreen.finalbitmap.recycle();
if(GameOverScreenCustom.finalbitmap != null)
GameOverScreenCustom.finalbitmap.recycle();
System.gc();
super.onDestroy();
}
public static Bitmap SavePixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.RGB_565);
return sb;
}
public GLGraphics getGLGraphics() {
return glGraphics;
}
#Override
public Input getInput() {
return input;
}
#Override
public FileIO getFileIO() {
return fileIO;
}
#Override
public Graphics getGraphics() {
throw new IllegalStateException("We are using OpenGL!");
}
#Override
public Audio getAudio() {
return audio;
}
#Override
public void setScreen(Screen screen) {
if (screen == null)
throw new IllegalArgumentException("Screen must not be null");
this.screen.pause();
this.screen.dispose();
screen.resume();
screen.update(0);
this.screen = screen;
}
#Override
public Screen getCurrentScreen() {
return screen;
}
#SuppressWarnings("deprecation")
#Override
protected void onActivityResult(int requestCode,int resultCode,Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
fb.authorizeCallback(requestCode, resultCode, data);
}
}
I figured out the answer by wrapping the Alert in a new thread
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle("");
alert.setMessage("");
alert.setPositiveButton("Buy", new OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
}
});
alert.setNegativeButton("Cancel", new OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
}
});
alert.show();
}
});