Android java crash screen recording - java

I have the following code that allows you to record what happens on the screen.
It works, but there are some problems and unforeseen events that happen and I do not understand which set of situations allow that app to crash.
To make one of the problems happen, the steps are as follows:
Press the start button
Start recording
Press the stop button
Wait a few moments
Press the start button again
Error:
E/MediaRecorder: SurfaceMediaSource could not be initialized!
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app, PID: 4465
java.lang.IllegalStateException: failed to get surface
at android.media.MediaRecorder.getSurface(Native Method)
at com.app.MainActivity2.getVirtualDisplay(MainActivity2.java:170)
at com.app.MainActivity2.startRecording(MainActivity2.java:71)
at com.app.MainActivity2.access$100(MainActivity2.java:23)
at com.app.MainActivity2$1.onClick(MainActivity2.java:47)....
Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Code:
package com.app;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity2 extends AppCompatActivity {
private static final int CAST_PERMISSION_CODE = 22;
private DisplayMetrics mDisplayMetrics;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private MediaRecorder mMediaRecorder;
private MediaProjectionManager mProjectionManager;
private boolean startRec = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mDisplayMetrics = new DisplayMetrics();
mMediaRecorder = new MediaRecorder();
mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
Button start = (Button) findViewById(R.id.start);
start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!startRec) startRecording();
}
});
Button stop = (Button) findViewById(R.id.stop);
stop.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (startRec) stopRecording();
}
});
}
private void startRecording() {
startRec = true;
// If mMediaProjection is null that means we didn't get a context, lets ask the user
Log.w("class:", "startRecording:start");
if (mMediaProjection == null) {
// This asks for user permissions to capture the screen
Log.w("class:", "startRecording:startResult");
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), CAST_PERMISSION_CODE);
Log.w("class:", "startRecording:endResult");
return;
}
Log.w("class:", "startRecording:end");
mVirtualDisplay = getVirtualDisplay();
mMediaRecorder.start();
}
private void stopRecording() {
startRec = false;
Log.w("class:", "stopRecording:start");
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.reset();
//mMediaRecorder = null;
}
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
//mVirtualDisplay = null;
}
if (mMediaProjection != null) {
mMediaProjection.stop();
//mMediaProjection = null;
}
Log.w("class:", "stopRecording:end");
}
public String getCurSysDate() {
return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
}
private void prepareRecording(String name) {
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
Toast.makeText(this, "Failed to get External Storage", Toast.LENGTH_SHORT).show();
return;
}
final String directory = Environment.getExternalStorageDirectory() + File.separator + "Recordings";
final File folder = new File(directory);
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
if (!success) {
Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
return;
}
String videoName = (name + "_" + getCurSysDate() + ".mp4");
String filePath = directory + File.separator + videoName;
int width = mDisplayMetrics.widthPixels;
int height = mDisplayMetrics.heightPixels;
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncodingBitRate(8000 * 1000);
mMediaRecorder.setVideoFrameRate(24);
mMediaRecorder.setVideoSize(width, height);
mMediaRecorder.setOutputFile(filePath);
try {
mMediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != CAST_PERMISSION_CODE) {
// Where did we get this request from ? -_-
Log.w("class:", "Unknown request code: " + requestCode);
return;
}
Log.w("class:", "onActivityResult:resultCode");
if (resultCode != RESULT_OK) {
startRec = false;
Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
return;
}
prepareRecording("start");
mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
Log.w("class:", "onActivityResult:mMediaProjection");
// TODO Register a callback that will listen onStop and release & prepare the recorder for next recording
// mMediaProjection.registerCallback(callback, null);
mVirtualDisplay = getVirtualDisplay();
mMediaRecorder.start();
}
private VirtualDisplay getVirtualDisplay() {
int screenDensity = mDisplayMetrics.densityDpi;
int width = mDisplayMetrics.widthPixels;
int height = mDisplayMetrics.heightPixels;
return mMediaProjection.createVirtualDisplay(this.getClass().getSimpleName(),
width, height, screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
}
}
Xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="#+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop" />
</LinearLayout>

Related

Reading values from Arduino IDE in Android Studio(java) ? There is no mistake as I can see but ıt doesn't work

Have a healthy day. As I mentioned in title, I want to read values from Arduino IDE (ESP32) . I ınstall nRF Connect mobile app because ı want to check if ı'm getting value correctly or not . I got true value.Then I write an android studio code as a beginner and from tutorials ofc. It's pairing devices and then if its name ESP32, ı wanna communicate it with arduiono but ı m getting empty array.After watching tutorials and reading stackoverflow posts ı ve decided to ask for help here. I will be glad if you help me. Thanks.
import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import pl.bclogic.pulsator4droid.library.PulsatorLayout;
public class MainActivity extends AppCompatActivity {
BluetoothAdapter myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
ArrayAdapter<String> arrayAdapter;
ArrayList<String> stringArrayList = new ArrayList<String>();
private boolean alreadyExecuted = false;
private boolean alreadyExecuted2=false;
BluetoothSocket mmSocket;
BluetoothServerSocket mmServerSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Thread workerThread;
TextView myLabel;
#SuppressLint("MissingPermission")
private void connectAndTransferDataBT(BluetoothDevice mmDevice) throws IOException{
BluetoothSocket tmp = null;
InputStream tmpIn = null;
OutputStream tmpOut = null;
Handler handler = new Handler();
UUID uuid = UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
try {
tmp = mmDevice.createRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
e.printStackTrace();
}
mmSocket = tmp;
try {
mmSocket.connect();
} catch (IOException e) {
e.printStackTrace();
}
try {
tmpIn = mmSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
tmpOut = mmSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInputStream = tmpIn;
mmOutputStream = tmpOut;
byte [] mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
assert mmInputStream != null;
numBytes = mmInputStream.read(mmBuffer);
};
private void getLocationPermission()
{
ActivityResultLauncher<String[]> locationPermissionRequest =
registerForActivityResult(new ActivityResultContracts
.RequestMultiplePermissions(), result -> {
Boolean fineLocationGranted = result.getOrDefault(
Manifest.permission.ACCESS_FINE_LOCATION, false);
Boolean coarseLocationGranted = result.getOrDefault(
Manifest.permission.ACCESS_COARSE_LOCATION,false);
if (fineLocationGranted != null && fineLocationGranted) {
} else if (coarseLocationGranted != null && coarseLocationGranted)
{
} else
{
}
}
);
locationPermissionRequest.launch(new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
});
}
public void statusCheck() {
final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
buildAlertMessageNoGps();
}
}
private void buildAlertMessageNoGps() {
if(!alreadyExecuted) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
Toast.makeText(MainActivity.this, "You have to enable your GPS for using Bluetooth!", Toast.LENGTH_SHORT).show();
dialog.cancel();
}
});
final AlertDialog alert = builder.create();
alert.show();
alreadyExecuted = true;
}
}
#SuppressLint("MissingPermission")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myBluetoothAdapter =BluetoothAdapter.getDefaultAdapter();
Button scanningBtn = findViewById(R.id.scanningBtn);
ListView listView = findViewById(R.id.listView);
LocationManager lm = (LocationManager)getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
boolean gps_enabled = false;
boolean network_enabled = false;
PulsatorLayout pulsator = findViewById(R.id.pulsator);
TextView myLabel = findViewById(R.id.myLabel);
if(myBluetoothAdapter == null)
{
Toast.makeText(this, "Bluetooth Is Not Available on this Device!", Toast.LENGTH_SHORT).show();
}
else
{
if(!myBluetoothAdapter.isEnabled())
{
//later
}
else
{
if(myBluetoothAdapter.isEnabled() && !myBluetoothAdapter.isDiscovering())
{
Intent intent = new Intent ( BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(intent,1);
statusCheck();
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
catch(Exception ex) {}
try {
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
catch(Exception ex) {}
if(!gps_enabled) {
buildAlertMessageNoGps();
}
getLocationPermission();
BroadcastReceiver myReceiver = new BroadcastReceiver() {
#SuppressLint("MissingPermission")
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action))
{
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(!stringArrayList.contains("Device : "+device.getName())) {
stringArrayList.add("Device : " + device.getName());
if(!alreadyExecuted2)
{if (device.getName().equals("ESP32")) {
mmDevice = device;
alreadyExecuted2=true;
}}
arrayAdapter.notifyDataSetChanged();
}
}
}
};
scanningBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//scanningBtn.setEnabled(false);
pulsator.start();
myBluetoothAdapter.startDiscovery();
if(mmDevice!=null)
{
try {
connectAndTransferDataBT(mmDevice);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(myReceiver,intentFilter);
arrayAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1,stringArrayList);
listView.setAdapter(arrayAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String s = listView.getItemAtPosition(position).toString();
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//startActivity(new Intent(MainActivity.this,MainScreenActivity.class));
}
});
}
}
}
}
}
xml code
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
android:background="#color/white"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView3"
android:layout_width="match_parent"
android:layout_height="140dp"
android:layout_marginTop="25dp"
/>
<Button
android:id="#+id/scanningBtn"
android:layout_width="140dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="25dp"
android:layout_marginBottom="17dp"
android:text="SCAN" />
<TextView
android:id="#+id/myLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
<pl.bclogic.pulsator4droid.library.PulsatorLayout
android:id="#+id/pulsator"
android:layout_width="match_parent"
android:layout_height="150dp"
app:pulse_count="4"
app:pulse_duration="3000"
app:pulse_interpolator="Accelerate"
android:layout_marginBottom="17dp"
app:pulse_repeat="0"
app:pulse_startFromScratch="false" />
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="530dp"
android:background="#color/white"
android:cacheColorHint="#FBF8F8" />
</LinearLayout>
</ScrollView>
</LinearLayout><![CDATA[
/>
]]>
</androidx.appcompat.widget.LinearLayoutCompat>
and arduino code from examples BLE_notify
/*
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-
snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
updated by chegewara
Create a BLE server that, once we receive a connection, will send periodic
notifications.
The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8
The design of creating the BLE server is:
1. Create a BLE Server
2. Create a BLE Service
3. Create a BLE Characteristic on the Service
4. Create a BLE Descriptor on the characteristic
5. Start the service.
6. Start advertising.
A connect hander associated with the server starts a background task that performs
notification
every couple of seconds.
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("ESP32");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
// https://www.bluetooth.com/specifications/gatt/viewer?
attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
// Create a BLE Descriptor
pCharacteristic->addDescriptor(new BLE2902());
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
BLEDevice::startAdvertising();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
float temp = 25.5;
char send[8];
dtostrf(temp,2,1,send);
pCharacteristic->setValue((uint8_t*)&send, 4);
pCharacteristic->notify();
value++;
delay(1000); // bluetooth stack will go into congestion, if too many packets are
sent, in 6 hours test i was able to go as low as 3ms
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
Your ESP32 code is Bluetooth Low Energy while your Android code is Bluetooth Classic.
You have to implement BLE in your android code
https://developer.android.com/guide/topics/connectivity/bluetooth/ble-overview

Capture Image From Camera using intent creates empty Image file

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>

How to replace LinearLayout with a layout that does not restrict element position in my code?

I have been experimenting with this code for a college project. The code uses "LinearLayout" which restricts me from freely moving my elements in the xml design editor so any changes that i make with it are overwritten by the linear layout in java. How could i reform this code?
class: MainActivity.java:
package com.android.audiorecordtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Layout;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG = "AudioRecordTest";
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
private static String fileName = null;
private RecordButton recordButton = null;
private MediaRecorder recorder = null;
private PlayButton playButton = null;
private MediaPlayer player = null;
// Requesting permission to RECORD_AUDIO
private boolean permissionToRecordAccepted = false;
private String [] permissions = {Manifest.permission.RECORD_AUDIO};
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case REQUEST_RECORD_AUDIO_PERMISSION:
permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
break;
}
if (!permissionToRecordAccepted ) finish();
}
private void onRecord(boolean start) {
if (start) {
startRecording();
} else {
stopRecording();
}
}
private void onPlay(boolean start) {
if (start) {
startPlaying();
} else {
stopPlaying();
}
}
private void startPlaying() {
player = new MediaPlayer();
try {
player.setDataSource(fileName);
player.prepare();
player.start();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
}
private void stopPlaying() {
player.release();
player = null;
}
private void startRecording() {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
recorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
recorder.start();
}
private void stopRecording() {
recorder.stop();
recorder.release();
recorder = null;
}
class RecordButton extends Button {
boolean mStartRecording = true;
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
onRecord(mStartRecording);
if (mStartRecording) {
setText("Stop recording");
} else {
setText("Start recording");
}
mStartRecording = !mStartRecording;
}
};
public RecordButton(Context ctx) {
super(ctx);
setText("Start recording");
setOnClickListener(clicker);
}
}
class PlayButton extends Button {
boolean mStartPlaying = true;
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
onPlay(mStartPlaying);
if (mStartPlaying) {
setText("Stop playing");
} else {
setText("Start playing");
}
mStartPlaying = !mStartPlaying;
}
};
public PlayButton(Context ctx) {
super(ctx);
setText("Start playing");
setOnClickListener(clicker);
}
}
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Record to the external cache directory for visibility
fileName = getExternalCacheDir().getAbsolutePath();
fileName += "/audiorecordtest.3gp";
ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION);
LinearLayout ll = new LinearLayout(this);
recordButton = new RecordButton(this);
ll.addView(recordButton,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0));
playButton = new PlayButton(this);
ll.addView(playButton,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0));
setContentView(ll);
}
#Override
public void onStop() {
super.onStop();
if (recorder != null) {
recorder.release();
recorder = null;
}
if (player != null) {
player.release();
player = null;
}
}
}
This is the XML code, basically auto-generated. Whatever changes are made are not active in the app because of the way java code is written and this is the problem.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"/>
This is a required permission added in the manifest file:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
I basically want to replace "LinearLayout" with something that does not restrict me from using XML while retaining all the code's functionality.
You need to set the orientation to your LinearLayout. You can try the code below. Also, you should try to use XML to design your layout, until your layout is not very dynamic.
layout.setOrientation(LinearLayout.VERTICAL);
Set Orientation in LinearLayout , Vertical or Horizontal.
linearLayout.setOrientation(LinearLayout.VERTICAL);
Use RelativeLayoute instead of LinearLayout in XML.
Below line is replacing your xml code at runtime.
setContentView(ll)
So you need to set just your xml file content like.
setContentView(R.layout.your_xml_file_name);
Buttons which you are creating in java file. You don't have to do this. Just add the buttons to xml file and set that xml file contents like above and Implement the OnClickListener in java file and setOnClickListener to those buttons also add the respective functionality to those button at onClick event.

Nothing happens when I click "Browse Image" on my webview app

Recently I made webview app on Android Studio. And I notice weird problem: When user click on "Browse Image" link nothing happens. I am trying to make a code so user can choose file from their Gallery on mobile phone.
emulator screenshot
Here is my MainActivity.java
package com.ijust2.ijust2;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.io.File;
public class MainActivity extends Activity {
private WebView webView;
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE=1;
private static final int PICK_IMAGE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new myWebClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("http://ijust2.com");
}
public class myWebClient extends WebViewClient
{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
#Override
// This method is used to detect back button
public void onBackPressed() {
if(webView.canGoBack()) {
webView.goBack();
} else {
// Let the system handle the back button
super.onBackPressed();
}
}
}
my activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ijust2.ijust2.MainActivity">
<WebView
android:id="#+id/webView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>
Can anyone give me some tips or suggest what should I do. I am newbie.
Thanks, Edi
I found a solution. Here is a code:
package it.floryn90.webapp;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends ActionBarActivity {
private static final int INPUT_FILE_REQUEST_CODE = 1;
private static final int FILECHOOSER_RESULTCODE = 1;
private static final String TAG = MainActivity.class.getSimpleName();
private WebView webView;
private WebSettings webSettings;
private ValueCallback<Uri> mUploadMessage;
private Uri mCapturedImageURI = null;
private ValueCallback<Uri[]> mFilePathCallback;
private String mCameraPhotoPath;
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
Uri[] results = null;
// Check that the response is a good one
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
// If there is not data, then we may have taken a photo
if (mCameraPhotoPath != null) {
results = new Uri[]{Uri.parse(mCameraPhotoPath)};
}
} else {
String dataString = data.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
}
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
if (requestCode != FILECHOOSER_RESULTCODE || mUploadMessage == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == this.mUploadMessage) {
return;
}
Uri result = null;
try {
if (resultCode != RESULT_OK) {
result = null;
} else {
// retrieve from the private variable if the intent is null
result = data == null ? mCapturedImageURI : data.getData();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "activity :" + e,
Toast.LENGTH_LONG).show();
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
return;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webview);
webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setAllowFileAccess(true);
webView.setWebViewClient(new Client());
webView.setWebChromeClient(new ChromeClient());
if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
else if(Build.VERSION.SDK_INT >=11 && Build.VERSION.SDK_INT < 19) {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.loadUrl("http://example.com"); //change with your website
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File imageFile = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
return imageFile;
}
public class ChromeClient extends WebChromeClient {
// For Android 5.0
public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> filePath, WebChromeClient.FileChooserParams fileChooserParams) {
// Double check that we don't have any existing callbacks
if (mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePath;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(TAG, "Unable to create Image File", ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
} else {
takePictureIntent = null;
}
}
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("image/*");
Intent[] intentArray;
if (takePictureIntent != null) {
intentArray = new Intent[]{takePictureIntent};
} else {
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
return true;
}
// openFileChooser for Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
// Create AndroidExampleFolder at sdcard
// Create AndroidExampleFolder at sdcard
File imageStorageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)
, "AndroidExampleFolder");
if (!imageStorageDir.exists()) {
// Create AndroidExampleFolder at sdcard
imageStorageDir.mkdirs();
}
// Create camera captured image file path and name
File file = new File(
imageStorageDir + File.separator + "IMG_"
+ String.valueOf(System.currentTimeMillis())
+ ".jpg");
mCapturedImageURI = Uri.fromFile(file);
// Camera capture image intent
final Intent captureIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
// Create file chooser intent
Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
// Set camera intent to file chooser
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS
, new Parcelable[] { captureIntent });
// On select image call onActivityResult method of activity
startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
}
// openFileChooser for Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
//openFileChooser for other Android versions
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType,
String capture) {
openFileChooser(uploadMsg, acceptType);
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
public class Client extends WebViewClient {
ProgressDialog progressDialog;
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// If url contains mailto link then open Mail Intent
if (url.contains("mailto:")) {
// Could be cleverer and use a regex
//Open links in new browser
view.getContext().startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
// Here we can open new activity
return true;
}else {
// Stay within this webview and load url
view.loadUrl(url);
return true;
}
}
//Show loader on url load
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// Then show progress Dialog
// in standard case YourActivity.this
if (progressDialog == null) {
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.show();
}
}
// Called when all page resources loaded
public void onPageFinished(WebView view, String url) {
try {
// Close progressDialog
if (progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}

How to put a progress bar with thread safety in android while hitting a server and waiting for response?

I have an application where I am recording audio in an activity. User has a start recording and stop recording button to do that. Once user clicks the stop recording button, it sends the recorded mp3 file to server (encoded string) and server process it and a response is received. I want to do the following tasks:
Since this process is long, I want to do this in a separate thread(preferably).
The process of sending and receiving response is to be shown using progress bar.
User should be able to navigate to other screens while he is waiting(i.e. current activity may be destroyed)
I tried using Toast messages before and after the function where I send mp3 to server. But there is no sync, sometimes msg comes early, sometime it's late. That's why a proper progress bar is required.How to do this? Can AsyncTask be used with what I want to achieve in (3). or should I use some other form of multithreading. Please help.Below is the activity
(Please ignore the indentations, I couldn't fix the code on stack-overflow:
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class RecordActivity extends AppCompatActivity {
private static final String LOG_TAG = "AudioRecordTest";
private static String msg = "default";
public final static String Result_MESSAGE = "in.innovatehub.ankita_mehta.tinyears.ResultMESSAGE";
private static final int REQUESTCODE_RECORDING = 109201;
private Button mRecorderApp = null;
private static String mFileName = "music.mp3";
private static String mFilePath = String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/TinyEars/"));
private MediaRecorder mRecorder = null;
private MediaPlayer mPlayer = null;
private ImageButton mRecordImageButton = null;
private ImageButton mPlayImageButton = null;
boolean mStartRecording = true;
boolean mStartPlaying = true;
private Button mShowStatsButton = null;
private static final String TAG = "RecordActivity";
private Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
handler.postDelayed(this, 1);
if(mRecorder!=null) {
int maxAmplitude = mRecorder.getMaxAmplitude();
if (maxAmplitude != 0) {
// visualizerView.addAmplitude(maxAmplitude);
}
}
else{
}
}
};
private void onRecord(boolean start) {
if (start) {
startRecording();
} else {
stopRecording();
}
}
private void onPlay(boolean start) {
if (start) {
startPlaying();
} else {
stopPlaying();
}
}
private void startPlaying() {
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mFilePath+"/"+mFileName);
mPlayer.prepare();
mPlayer.start();
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
Log.i("Completion Listener", "Song Complete");
stopPlaying();
mRecordImageButton.setEnabled(true);
}
});
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
}
private void stopPlaying() {
if (mPlayer != null) {
mPlayer.reset();
mPlayer.release();
mPlayer = null;
mPlayImageButton.setImageResource(R.drawable.playicon);
// mStartPlaying = true;
} else {
mPlayImageButton.setImageResource(R.drawable.pauseicon);
// mStartPlaying = false;
}
}
private void startRecording() {
AudioRecordTest(String.valueOf(System.currentTimeMillis()));
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setOutputFile(mFilePath+"/"+mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
try {
mRecorder.start();
Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e(LOG_TAG, "start() failed");
}
}
private void stopRecording() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
Toast.makeText(getApplicationContext(), "Audio recorded successfully",Toast.LENGTH_LONG).show();
mRecorder = null;
mRecordImageButton.setImageResource(R.drawable.micicon);
// mStartRecording = true;
} else {
mRecordImageButton.setImageResource(R.drawable.stopicon);
// mStartRecording = false;
}
}
public void AudioRecordTest(String text) {
boolean exists = (new File(mFilePath+"/"+mFileName)).exists();
if (!exists) {
new File(mFileName).mkdirs();
}
// mFileName += "audiorecordtest.mp3";
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record);
Log.d(TAG,"HERE IS FILE PATH"+mFilePath+"/"+mFileName);
mRecordImageButton = (ImageButton) findViewById(R.id.imageButton2);
mPlayImageButton = (ImageButton) findViewById(R.id.imageButton3);
mShowStatsButton = (Button) findViewById(R.id.showMeStats);
mRecorderApp = (Button) findViewById(R.id.recorderApp);
AudioRecordTest("00000");
mRecordImageButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
onRecord(mStartRecording);
if (mStartRecording) {
mRecordImageButton.setImageResource(R.drawable.stopicon);
mPlayImageButton.setEnabled(false);
//setText("Stop recording");
} else {
mRecordImageButton.setImageResource(R.drawable.micicon);
mPlayImageButton.setEnabled(true);
mShowStatsButton.setEnabled(true);
mShowStatsButton.setVisibility(View.VISIBLE);
Toast.makeText(getApplicationContext(),"Hold on... we are getting the results!",Toast.LENGTH_SHORT).show();
pressedSavBtn();
Toast.makeText(getApplicationContext(),"Parsing done ... now you may see the results!",Toast.LENGTH_SHORT).show();
//setText("Start recording");
}
mStartRecording = !mStartRecording;
}
});
mPlayImageButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
onPlay(mStartPlaying);
if (mStartPlaying) {
mPlayImageButton.setImageResource(R.drawable.pauseicon);
mRecordImageButton.setEnabled(false);
mShowStatsButton.setEnabled(false);
//setText("Stop playing");
} else {
mPlayImageButton.setImageResource(R.drawable.playicon);
mRecordImageButton.setEnabled(true);
mShowStatsButton.setEnabled(false);
//setText("Start playing");
}
mStartPlaying = !mStartPlaying;
}
});
//Calling recorder ...
mRecorderApp.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
if (isAvailable(getApplicationContext(), intent)) {
startActivityForResult(intent, REQUESTCODE_RECORDING);
}
}
});
mShowStatsButton = (Button) findViewById(R.id.showMeStats);
mShowStatsButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
sendResults(msg);
}
});
}
public void pressedSavBtn(){
try {
thread.start();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
mShowStatsButton.setVisibility(View.VISIBLE);
}
}
public void writeToFile(String data)
{
// Get the directory for the user's public pictures directory.
final File path = new File(mFilePath+"/");
// Make sure the path directory exists.
if(!path.exists())
{
// Make it, if it doesn't exit
path.mkdirs();
}
final File file = new File(path, "config.txt");
// Save your stream, don't forget to flush() it before closing it.
try
{
file.createNewFile();
FileOutputStream fOut = new FileOutputStream(file);
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.append(data);
myOutWriter.close();
fOut.flush();
fOut.close();
}
catch (IOException e)
{
Log.e("Exception", "File write failed: " + e.toString());
}
}
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append((line + "\n"));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
//THIS IS FILE ENCODING CODE
File file = new File(mFilePath+"/"+mFileName);
byte[] bytes = FileUtils.readFileToByteArray(file);
String encoded = Base64.encodeToString(bytes, 0);
Log.d("~~~~~~~~ Encoded: ", encoded);
writeToFile(encoded);
//THIS IS URL CONN CODE
String link = "http://192.168.50.0:9000/divide_result";
URL url = new URL(link);
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(link);
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("Name", "StackOverFlow"));
nameValuePairs.add(new BasicNameValuePair("Date", encoded));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
String sb = convertStreamToString(response.getEntity().getContent());
Log.d(TAG,"MESSAGE NOW"+sb);
Log.d(TAG, sb);
msg = sb.toString();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
public void sendResults(String res){
Log.d(TAG, "Inside on create, Navigating to Result Screen Activity!");
Intent intent = new Intent(getApplicationContext(), ResultsScreenActivity.class);
intent.putExtra(Result_MESSAGE, res);
startActivity(intent);
}
public static boolean isAvailable(Context ctx, Intent intent) {
final PackageManager mgr = ctx.getPackageManager();
List<ResolveInfo> list = mgr.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUESTCODE_RECORDING) {
if (resultCode == RESULT_OK) {
Uri audioUri = intent.getData();
// make use of this MediaStore uri
// e.g. store it somewhere
}
else {
// react meaningful to problems
}
}
else {
super.onActivityResult(requestCode,
resultCode, intent);
}
}
#Override
public void onPause() {
super.onPause();
if (mRecorder != null) {
mRecorder.release();
mRecorder = null;
}
if (mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
thread.stop();
}
#Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(updater);
if(mRecorder!=null) {
mRecorder.stop();
mRecorder.reset();
mRecorder.release();
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
handler.post(updater);
}
}
Also below is the layout-xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|center_horizontal"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:screenOrientation="portrait"
android:orientation="vertical"
tools:context="in.innovatehub.mobile.ankita_mehta.tinyears.RecordActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/linearLayout_record"
android:orientation="vertical"
android:gravity="center">
<ImageButton
android:id="#+id/imageButton2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:scaleType="fitXY"
android:src="#drawable/micicon" />
<ImageButton
android:id="#+id/imageButton3"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:scaleType="fitXY"
android:src="#drawable/playicon" />
<Button
android:id="#+id/showMeStats"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="gone"
android:onClick="loadStats"
android:text="#string/showMeStats" />
<Button
android:id="#+id/recorderApp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:gravity="center"
android:text="#string/UseRecorderApp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/loadStatsLinearLayout"
android:gravity="center"
android:visibility="gone"
android:orientation="vertical">
<TextView
android:id="#+id/loadingMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/loadingMessage"
/>
<ProgressBar
android:id="#+id/downloadProgress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
/>
</LinearLayout>
</LinearLayout>
You can use an IntentService to upload your content to the server. By default, it runs on a seperate thread and is not activity bound. Then use a broadcast receiver to communicate the result back to any activity. You can find an example here.
For the progress bar, you can create a notification and show the progress bar there, this will not block your application's UI.
For hitting the server at you should use AsyncTask or Runnable thread, without disturb the main tread
for custome progress dialog use the following code
xml file.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="#color/color_white"
android:padding="5dp" >
<ProgressBar
android:id="#+id/layCustomContentProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/layCustomProgressHeading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/layCustomProgressInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
and the method
public Dialog getCustomPogressDialog(Context context, String heading, String text) {
// Declare the customer dialog
Dialog dlgProgress = new Dialog(context);
// Set no title for the dialog
dlgProgress.requestWindowFeature(Window.FEATURE_NO_TITLE);
// Set the content view to the customer_alert layout
dlgProgress.setContentView(R.layout.layout_custom_process_progress);
// Cancel the dialog when touched outside.
dlgProgress.setCanceledOnTouchOutside(false);
// Set the main heading
TextView dlgHeading = (TextView) dlgProgress.findViewById(R.id.layCustomProgressHeading);
dlgHeading.setText(heading);
// set the info
TextView dlgInfo = (TextView) dlgProgress.findViewById(R.id.layCustomProgressInfo);
dlgInfo.setText(text);
// Return the refenrece to the dialog
return dlgProgress;
}

Categories

Resources