I am building a lock screen app. I want to place a floating icon on Homescreen, which when clicked will lock the phone. I was able to implement the functionality of Locking the Phone using Device Manager API. Now I want to add a Floating Icon on Homescreen.
I tried using the solution recommended here:
What APIs are used to draw over other apps (like Facebook's Chat Heads)?
But this does not seem to be working in my case. It is not diplaying an icon on the homescreen ever after gaining SYSTEM OVERLAY Permission.
LockButtonService.java
public class LockButtonService extends Service {
private WindowManager windowManager;
private ImageView chatHead;
#Override public IBinder onBind(Intent intent) {
// Not used
return null;
}
#Override public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.lock);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 100;
windowManager.addView(chatHead, params);
}
#Override
public void onDestroy() {
super.onDestroy();
if (chatHead != null) windowManager.removeView(chatHead);
}
}
MainActivity.java
add_homescreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Code For Adding Shortcut Icon On Home Screen
// if (ShortcutManagerCompat.isRequestPinShortcutSupported(getApplicationContext())) {
// ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(getApplicationContext(), "#1")
// .setIntent(new Intent(getApplicationContext(), LockActivity.class).setAction(Intent.ACTION_MAIN)) // !!! intent's action must be set on oreo
// .setShortLabel("Lock Screen")
// .setIcon(IconCompat.createWithResource(getApplicationContext(), R.drawable.lock))
// .build();
// ShortcutManagerCompat.requestPinShortcut(getApplicationContext(), shortcutInfo, null);
// } else {
// Toast.makeText(MainActivity.this,"launcher does not support short cut icon",Toast.LENGTH_LONG).show();
// }
//Code For Requesting System Overlay
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 12345);
}
else {
//Code To Execute If The Permission Is Granted
Toast.makeText(getApplicationContext(),"Permission Granted",Toast.LENGTH_LONG);
startService(new Intent(getApplicationContext(), LockButtonService.class));
}
}
}
I figured out the issue. It seems like I forgot to declare this service in Android Manifest. I was using WindowManager.LayoutParams.TYPE_PHONE in LockButtonService.java.
I have now changed it into WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, and my icon is displaying on homescreen and all other activities.
Related
I'm making an app where it uses intent to send data to another app. In case, the other app, which is supposed to receive data from my app, is not installed on users's device then it redirects user to play store with toast message asking user to install it. I used "if else" to achieve this. It worked all good until I found that if the other app is disabled by user (OEM installed app which can't be uninstalled), then my app crashes. In such a condition, I want to let user know that the app is disabled by them and ask them to enable it (through toast message). How can I achieve this?
Here is my complete code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creates button view which is connected to a view in the XML layout, which gets triggered on touching the view.
TextView textView = (TextView) findViewById(R.id.location);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Use package name which we want to check
boolean isAppInstalled = appInstalledOrNot("com.google.android.apps.maps");
if(isAppInstalled){
Uri gmmIntentUri = Uri.parse("geo:00,0000,00,0000");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
} else {
Uri uri2 = Uri.parse("market://details?id=com.google.android.apps.maps");
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri2);
Toast.makeText(MainActivity.this, "Google Maps not Installed", Toast.LENGTH_SHORT).show();
startActivity(goToMarket);
}
}
});
}
private boolean appInstalledOrNot(String uri) {
PackageManager pm = getPackageManager();
try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
return true;
} catch (PackageManager.NameNotFoundException e) {
}
return false;
}
}
I'm not sure if this will work for you, but since you know the package name, you could try this to do a check beforehand.
Hello StackOverflow's users,
I'm developing a Music Player App for android. In my main activity when the user clicks on a song I start a new intent that displays PlayerActivity. In there, I initialize a MediaPlayer and all the other UI elements. When the user clicks the back button, I bring them back to the main activity and the song continues to play in the background. The same thing happens if they exit the application. Now I was wondering if it's fine to do something like this or if I should instead start a new Service for the MediaPlayer from the PlayerActivity class instead of doing it in there.
PlayerActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
Bundle extras = getIntent().getExtras();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
getWindow().setNavigationBarColor(getResources().getColor(R.color.colorPrimaryDark));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
getWindow().setNavigationBarDividerColor(getResources().getColor(R.color.white));
}
playBtn = findViewById(R.id.btn_play);
artImage = findViewById(R.id.art);
remainingTimeLabel = findViewById(R.id.current_song_duration);
totalTimeLabel = findViewById(R.id.total_duration);
manager = MainActivity.getManager();
Song song = manager.getCurrentSong();
boolean wasCall = extras != null && extras.containsKey("call");
if (!wasCall && manager.hasStarted()) {
MediaPlayer mediaPlayer = manager.getMediaPlayer();
mediaPlayer.pause();
mediaPlayer.stop();
}
if (!wasCall) {
mp = MediaPlayer.create(this, Uri.parse(song.getPath()));
mp.setLooping(true);
mp.seekTo(0);
mp.setVolume(0.5f, 0.5f);
} else {
mp = manager.getMediaPlayer();
mp.setLooping(true);
mp.setVolume(0.5f, 0.5f);
}
totalTime = mp.getDuration();
artImage.setImageBitmap(Bitmap.createScaledBitmap(song.getIcon(), 250, 250, true));
totalTimeLabel.setText(createTimeLabel(totalTime));
songName = findViewById(R.id.songName);
songName.setText(song.getName());
songAuthor = findViewById(R.id.songAuthor);
songAuthor.setText(song.getArtist());
Toolbar toolbar = findViewById(R.id.player_top_bar);
toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
assert toolbar.getNavigationIcon() != null;
toolbar.getNavigationIcon().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setTitle(Html.fromHtml("<font color='#ffffff'>MySound</font>"));
positionBar = findViewById(R.id.seek_song_progressbar);
positionBar.setMax(totalTime);
positionBar.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mp.seekTo(progress);
positionBar.setProgress(progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
);
LinearLayout layout = findViewById(R.id.player_control);
layout.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
new Thread(() -> {
while (mp != null) {
try {
Message msg = new Message();
msg.what = mp.getCurrentPosition();
handler.sendMessage(msg);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
this.action = SongEndAction.REPEAT;
mp.start();
manager.setMediaPlayer(mp);
}
Here is a Music Service that I implemented in my book.
https://github.com/Wickapps/Practical-Android-MusicService
This implementation includes play, stop, and seek forward, but you could add other functions.
Service is the best architecture for future scalability.
There is a MainActivity.java which starts the service.
MusicService.java is the service implementation.
Hope this helps.
If you want your app to keep playing audio while it's in background ( like spotify ), then yes, it is a must to use a foreground service.
Unfortunately it's more complex than your current implementation.
This is a nice starting point : https://developer.android.com/guide/topics/media-apps/audio-app/building-an-audio-app
I have had a device, which apparently had something broken with the orientation, because after reboot, for about an hour, it would rotate the screen in response to a change of orientation - and then it would stop responding, both on the "desktop" level and application level.
So, I found Change Screen Orientation programmatically using a Button, and I assumed I can create a "icon button only" app, which when pressed, would not run a new application, but instead just try to change the orientation.
The skeleton for the "icon/button-only" app is a copy of Lock screen (it.reyboz.screenlock). I posted this project on a gist - but since it is hard to have folders (and binary files) by default in a gist, this is the procedure you can use to get the code:
git clone https://gist.github.com/e6422677cababc17526d0cb57aceb76a.git dl_archive_git
cd dl_archive_git
bash run-me-to-unpack.sh
# check upacked dir:
tree rotate-btn-droid
cd rotate-btn-droid/
# change your SDK path (ASDKPATH) in buildme.sh, and then:
bash buildme.sh
# if your java install is not in the path, then call the last command with JAVA_HOME prepended:
# JAVA_HOME=/path/to/jdkXXX bash buildme.sh
Basically, I'm just trying to do the following in MainActivity.java:
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int orientation = display.getOrientation();
// OR: orientation = getRequestedOrientation(); // inside an Activity
switch(orientation) {
case Configuration.ORIENTATION_PORTRAIT:
setRequestedOrientation (Build.VERSION.SDK_INT < 9 ?
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE :
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
break;
case Configuration.ORIENTATION_LANDSCAPE:
setRequestedOrientation (Build.VERSION.SDK_INT < 9 ?
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT :
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
break;
}
... however, nothing happens when I click the app icon and run this code.
So, my question is - is it possible in principle to force a change of the device orientation on a "desktop" level? If so, is it dependent on Android version (possibly vendor branded) or not - and how?
Was just curious so tried out Sam's solution and made some changes :
Would need this permission in Manifest
Permission <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Also this permissions is a dangerous permission but if you are installing the app from Play store you need not worry about that.
I made a window service something like this :
public class MyServiceNew extends Service {
private View view;
public MyServiceNew() {
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int flag = intent.getExtras().getInt("Flag");
WindowManager.LayoutParams layout;
if (flag == 1) {
layout = generateLayoutLandscape();
} else {
layout = generateLayoutPortrait();
}
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(view, layout);
return super.onStartCommand(intent, flags, startId);
}
private WindowManager.LayoutParams generateLayoutPortrait() {
Toast.makeText(this, "Port", Toast.LENGTH_LONG).show();
view = new View(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSPARENT);
params.alpha = 0f;
params.width = 0;
params.height = 0;
//The orientation to force
params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
return params;
}
private WindowManager.LayoutParams generateLayoutLandscape() {
Toast.makeText(this, "Land", Toast.LENGTH_LONG).show();
view = new View(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSPARENT);
params.alpha = 0f;
params.width = 0;
params.height = 0;
//The orientation to force
params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
return params;
}
}
And from your Activity while development make sure you include ACTION_MANAGE_OVERLAY_PERMISSION ; again you don't need to worry this for users who will install the app through Google Play Store. Here using the below code to allow permission for devices above M :
public void requestSystemAlertPermission(int requestCode) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
return;
final String packageName = getPackageName();
final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + packageName));
startActivityForResult(intent, requestCode);
}
And now just start your service and pass extras for Portrait or Landscape
I am using 1 for Landscape and 2 for Portrait
Intent intentLand = new Intent(SoNew.this, MyServiceNew.class);
intentLand.putExtra("Flag", 2); //or change 1 for Port
startService(intentLand);
Hope this helps :)
I have an android device, it can only run a app (like ATM screen). Now I want to implement the following feature:
If the device is not in use for over 30 minutes, I will adjust the screen brightness to the lowest. At this time, if I touch the screen, I should adjust the screen brightness to the maximum. The user can not see any Android system menu, application, etc. They only can use this app (can't close it). This app will run in this device from the power on it and power off it.
I don't how to implement this feature.
Thanks.
You can use a class that extends service and can dim the screen brightness. Use AlarmManager to check the time that the user never touches the screen. I will give you an example of using the Service class:
public class DimScreen extends Service {
public static int ID_NOTIFICATION = 2018;
private WindowManager windowManager;
private LinearLayout saverScreen;
private PopupWindow pwindo;
boolean mHasDoubleClicked = false;
long lastPressTime;
private Boolean _enable = true;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
saverScreen = new LinearLayout(this);
saverScreen.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
Bitmap sample = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
saverScreen.setBackground(new BitmapDrawable(this.getResources(),
convertColorIntoBlackAndWhiteImage(sample)));
saverScreen.setClickable(false);
saverScreen.setFocusable(false);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.FILL_PARENT,
PixelFormat.TRANSLUCENT);
params.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|WindowManager.LayoutParams.FLAG_DIM_BEHIND;
params.dimAmount = (float) 0.6;
params.screenBrightness = (float) 0.3;
params.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE;
windowManager.addView(saverScreen, params);
}
#Override
public void onDestroy() {
super.onDestroy();
if (saverScreen != null) windowManager.removeView(saverScreen);
}
private Bitmap convertColorIntoBlackAndWhiteImage(Bitmap orginalBitmap) {
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(2);
ColorMatrixColorFilter colorMatrixFilter = new ColorMatrixColorFilter(
colorMatrix);
Bitmap blackAndWhiteBitmap = orginalBitmap.copy(
Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
paint.setColorFilter(colorMatrixFilter);
Canvas canvas = new Canvas(blackAndWhiteBitmap);
canvas.drawBitmap(blackAndWhiteBitmap, 0, 0, paint);
return blackAndWhiteBitmap;
}
}
In your Activity class call
startService(new Intent(this,DimScreen.class));
You only have to implement the AlarmManager now. If the user never touches the screen, launch the Service class. If the user Interrupt with the app, then call stopService.
Try this
WindowManager.LayoutParams localLayoutParams = getWindow()
.getAttributes();
localLayoutParams.screenBrightness = 0.12F;
getWindow().setAttributes(localLayoutParams);
I have an application that I have taking a picture, and then it is supposed to send the data from the picture to another activity using an intent.
I am trying to call the intent inside the jpegCallback, but the problem is I also need to release the camera through the preview class before calling the intent. However, I can not get to the original preview object from inside the callback, so I need a way to call MainActivity.doPictureResults() from inside the callback. Or I need a way to have a listener that fires after all of the picture callbacks are done.
Here is my MainActivity class which holds an instance of Preview class in the mPreview variable. The jpegCallback is at the bottom, and I want to call the doPictureResults from inside that, or setup another callback for after that function is done.
public class MainActivity extends Activity {
private final String TAG = "MainActivity";
private Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
//The first rear facing camera
int defaultCameraId;
/**
* Constructor
* #param savedInstanceState
*/
#Override
protected void onCreate(Bundle savedInstanceState) {Log.e(TAG, "onCreate");
super.onCreate(savedInstanceState);
//Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
//Create a RelativeLayout container that will hold a SurfaceView,
//and set it as the content of our activity.
this.mPreview = new Preview(this);
setContentView(this.mPreview);
//Find the total number of cameras available
this.numberOfCameras = Camera.getNumberOfCameras();
//Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for(int i = 0; i < this.numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if(cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
this.defaultCameraId = i;
}
}
}
#Override
protected void onResume() {Log.e(TAG, "onResume");
super.onResume();
//Open the default i.e. the first rear facing camera.
this.mCamera = Camera.open();
this.cameraCurrentlyLocked = this.defaultCameraId;
this.mPreview.setCamera(mCamera);
}
#Override
protected void onPause() {Log.e(TAG, "onPause");
super.onPause();
//Because the Camera object is a shared resource, it's very
//Important to release it when the activity is paused.
this.mPreview.releaseCamera();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//Handle item selection
switch (item.getItemId()) {
case R.id.switchCam:
//Check for availability of multiple cameras
if(this.numberOfCameras == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(this.getString(R.string.camera_alert)).setNeutralButton("Close", null);
AlertDialog alert = builder.create();
alert.show();
return true;
}
//OK, we have multiple cameras.
//Release this camera -> cameraCurrentlyLocked
this.mPreview.releaseCamera();
//Acquire the next camera and request Preview to reconfigure parameters.
this.mCamera = Camera.open((this.cameraCurrentlyLocked + 1) % this.numberOfCameras);
this.cameraCurrentlyLocked = (this.cameraCurrentlyLocked + 1) % this.numberOfCameras;
this.mPreview.switchCamera(mCamera);
//Start the preview
this.mCamera.startPreview();
return true;
case R.id.takePicture:
this.mCamera.takePicture(null, null, jpegCallback);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void doPictureResults(byte[] data) {
this.mPreview.releaseCamera();
//Release the camera and send the results of the image to the GetResults view
Intent resultsIntent = new Intent(MainActivity.this, ImageProcessorActivity.class);
resultsIntent.putExtra("image_data", data);
startActivity(resultsIntent);
}
/**
* Handles data for jpeg picture when the picture is taken
*/
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera mCamera) {Log.e(TAG, "jpegCallback");
String baseExternalDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = String.format("Assist/%d.jpg", System.currentTimeMillis());
FileOutputStream outStream = null;
try {
//Create the directory if needed
File assistDirectory = new File(baseExternalDir + File.separator + "Assist");
assistDirectory.mkdirs();
// Write to SD Card
outStream = new FileOutputStream(baseExternalDir + File.separator + fileName);
outStream.write(data);
outStream.close();
}
catch (FileNotFoundException e) {
Log.e(TAG, "IOException caused by PictureCallback()", e);
}
catch (IOException e) {
Log.e(TAG, "IOException caused by PictureCallback()", e);
}
//This is the type of thing I WANT to do....but its not possible.
MainActivity.doPictureResults();
}
};
}
One options would be to create a PictureCallback implementation that saved the information was required in doPictureResults. It's not clear if doPictureResults will be called anywhere else; if it's not, this is clean and isolates the functionality.
Another would be to have the activity itself implement PictureCallback so you have direct access to all the member variables without having to do any work at all. This allows doPictureResults to be called from other places.
public class MainActivity extends Activity implements PictureCallback {
...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
....
case R.id.takePicture:
this.mCamera.takePicture(null, null, this);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
...
public void onPictureTaken(byte[] data, Camera mCamera) {
Log.d(TAG, "jpegCallback");
String baseExternalDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = String.format("%d.jpg", System.currentTimeMillis());
...
doPictureResults();
}
}
The only methods you can call on a class without an instance are static methods, but I don't know if that will do what you want here.