I try to create QR Code scanner in fragment, but camera won't showing in surfaceview and just turn black.
here's my java class:
public class ScanFragment extends Fragment {
SurfaceView surfaceView;
CameraSource cameraSource;
TextView textView;
BarcodeDetector barcodeDetector;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_scan, container, false);
surfaceView = (SurfaceView) view.findViewById(R.id.cameraPreview);
textView = (TextView) view.findViewById(R.id.scanText);
barcodeDetector = new BarcodeDetector.Builder(view.getContext().getApplicationContext())
.setBarcodeFormats(Barcode.QR_CODE).build();
cameraSource = new CameraSource.Builder(view.getContext().getApplicationContext(), barcodeDetector)
.setRequestedPreviewSize(640, 480).build();
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getContext().getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
cameraSource.start(holder);
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> qrCodes = detections.getDetectedItems();
if(qrCodes.size() != 0){
textView.post(new Runnable() {
#Override
public void run() {
Vibrator vibrator = (Vibrator) getContext().getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);
textView.setText(qrCodes.valueAt(0).displayValue);
}
});
}
}
});
return view;
}
}
I gave the uses permissions from the android manifest file. compiles seamlessly in android studio but when I run it on the phone the camera just turn black and no crash from that.
Anyone know how to fix this?
From Android 6.0(API 23) on, you need to request runtime permission from the users. That is why your camera doesn't show anything. Permission is only defined in AndroidManifest, but the user did not agree to allow your application to use a camera. You have a good example of how to request runtime permissions here.
If you want to read more about this, there is also documentation available on Android developer:
https://developer.android.com/distribute/best-practices/develop/runtime-permissions
https://developer.android.com/training/permissions/requesting
Related
Couldn't find a solution from the existing posts. I'm trying to build a step counter using Android's built in TYPE_STEP_COUNTER sensor but the onSensorChange() method doesn't get called! In the below code, for example, "Outside stepcount" is never printed to the Logcat.
public class StepFragment extends Fragment implements SensorEventListener {
private int step_count = 0;
TextView stepCountText;
private Sensor mStepSensor;
private SensorManager mSensorManager;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.stepfragment, container, false);
stepCountText = (TextView)view.findViewById(R.id.stepcounttext);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSensorManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);
mStepSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
public void onSensorChanged(SensorEvent event) {
System.out.println("Outside" + step_count);
if (event.values[0] == 1.0f) {
step_count++;
System.out.println(step_count);
}
stepCountText.setText(Integer.toString(step_count));
}
#Override
public void onResume() {
super.onResume();
mSensorManager.registerListener(this, mStepSensor, SensorManager.SENSOR_DELAY_NORMAL);
if(mStepSensor != null)
{
System.out.println("Sensor step counter present");
}
}
#Override
public void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
System.out.println("Fragment Paused");
}
}
I do get "Sensor step counter present" in my Logcat which proves that my device indeed has the step_counter sensor. I'd be very grateful for some help!
Here is full code of the app which freezes (UI) after some seconds of work.
Is something dangerous here?
Thank you!
public class FragmentOne extends Fragment {
private Context _context;
private View view;
private BroadcastReceiver broadcastReceiver;
public FragmentOne() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_fragment_one, container, false);
setup();
return view;
}
#Override
public void onAttach(Context context)
{
super.onAttach(context);
_context = context;
}
private void setup()
{
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent i)
{
try
{
DLocation dLocation = (DLocation) i.getExtras().get("coordinates");
if (dLocation != null) {
Log.d("Первый фрагмент", "Применение параметров шир. сообщения к контролам окна");
TextView textLon = (TextView)view.findViewById(R.id.textLon);
textLon.setText(dLocation.Longitude);
TextView textLat = (TextView)view.findViewById(R.id.textLat);
textLat.setText(dLocation.Latitude);
TextView textTime = (TextView)view.findViewById(R.id.textTime);
textTime.setText(dLocation.TimeOfRequest);
TextView textErrors = (TextView)view.findViewById(R.id.textErrors);
textErrors.setText(dLocation.Errors);
}
}
catch (Exception ex)
{
Toast.makeText(getActivity(), ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
};
_context.registerReceiver(broadcastReceiver, new IntentFilter("location_update"));
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
if (broadcastReceiver != null) {
_context.unregisterReceiver(broadcastReceiver);
}
}
}
Root Cause
I think you are using a 3rd party library to detect location. The library is receiving the GPS coordinates at a very high rate. These coordinates are then received by your broadcast receiver. Your broadcast receiver is doing it's work on the UI thread. The reason why your app freezes is because the UI thread is doing work at very high rate.
Solution
The solution to your problem lies in Bound Service. You can find code examples in android developer docs Bound Services.
For use cases like a music player, where media is played in a background thread but duration of played music is shown on the UI, bound service can be useful. I hope this sets you in the right direction.
My app currently looks like this:
I want to add a search bar where I can search any place as Google maps. The search bar should be in an Auto Complete way.I got this code from https://examples.javacodegeeks.com/android/android-google-places-autocomplete-api-example/
Have a look at the above link.
And these codes where for an ORDINARY APP to get Auto Complete search bar. It doesnt suit for app using fragment. And I dont know how to do it with fragments.
Here is my code
For the Main Activity (ProfileActivity)
public class ProfileActivity extends AppCompatActivity {
final String TAG = this.getClass().getName();
BottomBar mBottomBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
mBottomBar = BottomBar.attach(this, savedInstanceState);
mBottomBar.setItemsFromMenu(R.menu.menu_user, new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int i) {
if(i == R.id.ButtonBarFeed)
{
NewsFragment f = new NewsFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,f).commit();
}
else if(i == R.id.ButtonBarMap)
{
MapFragment f = new MapFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,f).commit();
}
else if(i == R.id.ButtonBarUser)
{
UserFragment f = new UserFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,f).commit();
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
}
});
mBottomBar.mapColorForTab(0,"#28809f");
}
public boolean googleServicesAvailable(){
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int isAvailable = api.isGooglePlayServicesAvailable(this);
if(isAvailable == ConnectionResult.SUCCESS){
return true;
}else if(api.isUserResolvableError(isAvailable)){
Dialog dialog = api.getErrorDialog(this, isAvailable, 0);
dialog.show();
} else {
Toast.makeText(this,"Can't connet to Play Services", Toast.LENGTH_LONG).show();
}
return false;
}
boolean twice;
#Override
public void onBackPressed() {
Log.d(TAG, "click");
if(twice == true){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
System.exit(0);
}
twice = true;
Log.d(TAG, "twice:" + twice);
Toast.makeText(ProfileActivity.this, "Please press BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
twice = false;
Log.d(TAG, "twice:" + twice);
}
}, 3000);
}
}
MapFragment
public class MapFragment extends Fragment implements OnMapReadyCallback {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.map, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SupportMapFragment fragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.mapView1);
fragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap){
}
}
I have to add a search bar with Auto Complete like Google map.Please with reference of the Link which I have given at starting, Can Anyone code for my MapFragment?
Question summary:
1) How to first display the video as paused, and not play it immediately?
2) How to pause/un-pause the video on touch, and also hide/show the ActionBar and MediaController.
I'd appreciate any advice. Thanks! (Relevant Code is attached)
Update 1
Found somewhat of a solution to question 2 (needed to return false), but I still don't know how to answer question 1.
When the user presses a button in my app, it takes them to watch their video. When they first open that screen, I'd like the video to be paused and not play immediately. I'd also like to be able to pause playback of the video by tapping the screen. When the video is paused, I'd like to show the ActionBar and the MediaController. When the video is resumed, I'd like to hide the ActionBar and MediaController (possibly after a slight delay?)
I've tried a few things, but I end up with problems, like the video will pause but not resume, or the ActionBar and MediaController will not show or hide properly.
Update 2
I have found a partial solution to question 1 and have updated the code to display the video as paused the first time it is opened. However, when it is opened for the first time, it only shows a black screen until I touch the videoview to play it. After watching the video once, it will reset to the beginning and pause, waiting to be played again, and will show the correct image from the beginning of the video. But I don't know how to get around the black screen at the beginning.
Relevant code:
public class ViewImageVideoFragment extends Fragment
{
private int position = 0;
private MediaController mMediaController;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mMediaController = new MediaController(getActivity());
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
position = savedInstanceState.getInt("position");
}
View v = inflater.inflate(R.layout.fragment_video_view, parent, false);
mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
mVideoView.setVideoPath(videoPath);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
if (mVideoView.isPlaying())
{
mVideoView.pause();
if (!getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().show();
mMediaController.show(0);
}
position = mVideoView.getCurrentPosition();
return false;
}
else
{
if (getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().hide();
mMediaController.hide();
}
mVideoView.seekTo(position);
mVideoView.start();
return false;
}
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
mVideoView.seekTo(0);
}
});
if (position != 0)
{
mVideoView.seekTo(position);
mVideoView.start();
}
else
{
mVideoView.seekTo(0);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
if (mVideoView != null)
{
savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
}
mVideoView.pause();
}
}
To first show the video as paused, simply change seekTo(0) to seekTo(1) in your code. This will move the video to the time at 1 millisecond and you can take it from there.
//edited here
private int position = 1;
private MediaController mMediaController;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mMediaController = new MediaController(getActivity());
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
position = savedInstanceState.getInt("position");
}
View v = inflater.inflate(R.layout.fragment_video_view, parent, false);
mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
mVideoView.setVideoPath(videoPath);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
if (mVideoView.isPlaying())
{
mVideoView.pause();
if (!getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().show();
mMediaController.show(0);
}
position = mVideoView.getCurrentPosition();
return false;
}
else
{
if (getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().hide();
mMediaController.hide();
}
mVideoView.seekTo(position);
mVideoView.start();
return false;
}
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
//here
mVideoView.seekTo(1);
}
});
//here
if (position != 1)
{
mVideoView.seekTo(position);
mVideoView.start();
}
else
{
//here
mVideoView.seekTo(1);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
if (mVideoView != null)
{
savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
}
mVideoView.pause();
}
}
If I understand correctly, you want to display a frame from the video as a placeholder until you are ready to start the video. There's two ways I know to accomplish this:
seekTo
You can use MediaPlayer.seekTo to move the video some frames ahead, for example using the value 150 to display the frame at the 150th millisecond in the video file. The video does not need to be started in order to seek.
MediaMetadataRetriever
MediaMetadataRetriever met = new MediaMetadataRetriever();
try {
met.setDataSource(data[0], new HashMap<String, String>()); //use this constructor, other one has a bug...
Bitmap b = met.getFrameAtTime();
if (b == null)
b = met.getFrameAtTime(150, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
met.release();
return b;
} catch (Exception e) {
Log.d(TAG, "MediaMetadata failed", e);
}
This will give you a Bitmap which you can then throw in an ImageView and set in place of the video. However, this API has always been buggy for me depending on the types of video codecs you are dealing with.
My sources --
show()
show(int timeout)
hide()
isShowing()
onTouchEvent()
All notes are in the code
public class ViewImageVideoFragment extends Fragment
{
private int position = 0;
private MediaController mMediaController;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mMediaController = new MediaController(getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
position = savedInstanceState.getInt("position");
}
v = inflater.inflate(R.layout.fragment_video_view, parent, false);
mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
mVideoView.setVideoPath(videoPath);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnTouchListener(
new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
if (mVideoView.isPlaying())
{
mVideoView.pause();
/*
Ok, so now you want to use that show(), preferrably without the int timeout
I didn't add it in myself but you should be able to handle it yourself
*/
return true;
}
else /* I changed it to else, change it to if else if you have something specific you want to deal with */
{
/*
I would use that hide method I linked here, then start the
video, I assume you know how to play the video yourself
*/
}
return false;
}
});
mVideoView.seekTo(position);
mVideoView.start();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
if (mVideoView != null)
{
savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
}
mVideoView.pause();
}
}
I provided the other methods because, depending on how you may continue, they may or may not prevent future questions.
I am trying to view a live streaming by motion on my Raspberry Pi through an Android App written with Android Studio...I have compound this code using mplayer:
public class MainActivity extends ActionBarActivity implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener {
private MediaPlayer mediaPlayer;
private SurfaceHolder vidHolder;
private SurfaceView vidSurface;
String vidAddress = "http://www.example.com/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vidSurface = (SurfaceView) findViewById(R.id.surfView);
vidHolder = vidSurface.getHolder();
vidHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDisplay(vidHolder);
mediaPlayer.setDataSource(vidAddress);
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
catch(Exception e){
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
}
}
But it does not work. If I put an url of a streaming video (not live) for example: www.something.com/vid.mp4 it works. (Yes, I have added internet permission on manifest). Anyone could help me?
Thanks!
I noticed you are inserting a web address without a file at the end - that might be your cause. Motion uses the file stream.mjpg, so the local address by default would be http://hostip:8081/stream.mjpg
Source: http://www.lavrsen.dk/foswiki/bin/view/Motion/MotionGuideBasicFeatures#Webcam_Server