I'm trying to have a unit test that checks whether the activity launched is in the correct orientation.
So, in my AndroidManifest.xml file, I have the orientation set as:
<activity
android:name="com.xxx.MyActivity"
android:screenOrientation="portrait"
android:theme="#style/MyTheme" >
<meta-data
android:name="target_device"
android:value="phone" />
</activity>
The tests and tested code are in the same project, so I assume Robolectric doesn't have any problems finding the manifest.
Besides, all the tests run fine except this one.
And here is my unit test:
ActivityController<MyActivity> activityController = Robolectric
.buildActivity(MyActivity.class)
.create()
.start()
.postCreate(null)
.resume()
.visible();
MyActivity mActivity = activityController.get();
assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, mActivity.getResources().getConfiguration().orientation);
The mActivity.getResources().getConfiguration().orientation is always 0, while portrait is 1.
Any idea why?
(using Robolectric 2.4)
Related
I am working on an well-being app that shuts your phone up for a given period of time (eg. 30min, 1hr, 1.5hr)
In this state user can only see a screen with remaining time on it and cannot
Access QS tiles
Access Volume panel
Navigate out of the Activity
something similar to Oneplus
Zen mode
things i have thought of for doing this
Killing the SystemUI process.(by doing so the QS and volume panel
would be dealt with most probably, maybe need root for that tho?
also SystemUI automatically restarts itself, quite stubborn)
Making app a launcher Dynamically?(technically you can't navigate
out of a launcher and on reboot you come back to it)
how can I get around accomplishing this? any ideas?
Making application the default launcher of the phone is more practical solution to what you're trying to achieve. I've done this previously in a Flutter application which was going to be installed on kiosk devices to get orders from customers and it worked perfectly. It's a bit tricky to make it work and there's lots of things to do. Here is a list of things I did back then:
Use FLAG_SHOW_WHEN_LOCKED flag to the window to bypass the lock screen.
Inside of onResume add FLAG_FULLSCREEN flags to hide the status bar.
Make your MainActivity launcher by adding LAUNCHER category to in AndroidManifest.xml. Also you can add other attributes I used (Search for them if you don't know what are they supposed to do).
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:excludeFromRecents="true"
android:hardwareAccelerated="true"
android:launchMode="singleInstance"
android:showOnLockScreen="true"
android:showWhenLocked="true"
android:theme="#style/LaunchTheme"
android:turnScreenOn="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Listen for window focus changes in your MainActivity and bring your application to front if it lost the focus.
private fun moveToFront() {
val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
sendBroadcast(closeDialog)
(activity.applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
.moveTaskToFront(activity.taskId, ActivityManager.MOVE_TASK_WITH_HOME)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (!hasFocus) {
moveToFront()
}
}
I was also checking if my application is the default launcher.
private fun isAppDefault(): Boolean {
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_HOME)
val res: ResolveInfo = packageManager.resolveActivity(intent, 0)
return res.activityInfo != null && (packageName
== res.activityInfo.packageName)
}
And you're gonna need to communicate between Flutter and the platform using MethodChannel to enable and disable force mode and get the state of the application.
I'm basically attempting to accomplish this, using the first answer provided. The question has answers around the web and SO, but I'm having trouble getting it to work. Is there something I need to enable, add to my manifest, ect.? I want to react to a beacon coming within range of the phone. I'm working in Android Studio, targeting Android 4.3 and working with the Android Beacon Library. Based on their documentation, all I need is to implement BootstrapNotifier, set a Region, and then anytime it scans a beacon, it will automatically call didEnterRegion. My Region is Region region = new Region("all-beacons-region", null, null, null);.
I have also built a very simple app which scans for and finds beacons in the foreground. So no problems there, I am definitely able to pick up my beacons and pull basic info from them.
My main activity looks like this:
package com.example.justin.backgroundscantest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
And my class looks like this:
import android.app.Application;
import android.content.Intent;
import android.util.Log;
import com.example.justin.backgroundscantest.MainActivity;
import org.altbeacon.beacon.startup.BootstrapNotifier;
import org.altbeacon.beacon.startup.RegionBootstrap;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Region;
public class TestApp extends Application implements BootstrapNotifier {
private static final String TAG = ".TestApp";
private RegionBootstrap regionBootstrap;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
// wake up the app when any beacon is seen (you can specify specific id filers in the parameters below)
Region region = new Region("com.example.myapp.boostrapRegion", null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
}
#Override
public void didEnterRegion(Region arg0) {
Log.d(TAG, "Got a didEnterRegion call");
// This call to disable will make it so the activity below only gets launched the first time a beacon is seen (until the next time the app is launched)
// if you want the Activity to launch every single time beacons come into view, remove this call.
regionBootstrap.disable();
Intent intent = new Intent(this, MainActivity.class);
// IMPORTANT: in the AndroidManifest.xml definition of this activity, you must set android:launchMode="singleInstance" or you will get two instances
// created when a user launches the activity manually and it gets launched from here.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
}
}
(Edit)
Finally, AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.justin.backgroundscantest">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
It all feels pretty straightforward, which is I'm curious if I'm missing something simple or silly. I've found this example in several places around the web, but no mention of anything that I might have missed. I have a pretty solid coding background but am new to Android and very new to Eddystone/BLE technology. And just to clarify the actual problem: there is no reaction from my app when I move the phone within range of the beacon. My expectation is that it will "wake up" and begin MainActivity. I am definitely in range of the beacon, the beacon is definitely on, and again, I am able to scan it in the foreground. It just won't wake up my app. Thanks!
When creating a custom Android Application class like TestApp, you must declare it in your manifest with a name attribute. Like this:
<application
android:name="TestApp"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
If you don't do that, Android won't use your custom TestApp class, and will instead default to its built-in base Application class, causing none of the TestApp code to get executed.
I have 2 product flavor. Let's say the example like this:
productFlavors {
free {
applicationId 'com.free.android'
}
premium {
applicationId 'com.premium.android'
}
My problem is when i use
Intent resultIntent = new Intent(this, ExpiryListActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ExpiryListActivity.class);
stackBuilder.addNextIntent(resultIntent);
The problem happened when stackBuilder.addParentStack(ExpiryListActivity.class)
The first app which used the productFlavor free doesn't cause android.content.pm.PackageManager$NameNotFoundException error.
But the second app which used the productFlavor premium it causes android.content.pm.PackageManager$NameNotFoundException.
Then i read the docs that stackBuilder.addParentStack(<Class>) Add the activity parent chain as specified by manifest . How to solve this problem?
TL;DR
change your metadata as
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="originalPackageName.ui.MainActivity" />
The basic problem is that gradle is expanding the package name for the parent activity class that you wrote in the metadata.
In case of your free product flavor it tries to find a class at location com.free.android.ui.MainActivity
And in case of your paid flavor it tries to find a class at location com.premium.android.ui.MainActivity
But gradle actually does not restructure the packages when you mention different applicationId's for your product flavors and the class is still located at originalPackageName.ui.MainActivity and hence the NameNotFoundException
where originalPackageName is a placeholder for the package name you started your project with.
Looks like i found it. On AndroidManifest.xml
<activity
android:name=".ui.ExpiryListActivity"
android:label="#string/voucher_expiry_list"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar.Slidable" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.MainActivity" />
</activity>
I replace the meta-data name by:
<activity
android:name=".ui.ExpiryListActivity"
android:label="#string/voucher_expiry_list"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar.Slidable" >
<meta-data
android:name=".ui.ExpiryListActivity"
android:value=".ui.MainActivity" />
</activity>
It works, but when pressing back it cannot return to MainActivity. But, I know if this is not the best solution. Please let me know if there is another better solution.
NB: This seems only happened on Android Lollipop (5.0)
I use the Library:
https://github.com/lvillani/android-cropimage
for adding crop activity in my project.I import this library and add in my project now I am writing this code :
String mPackage = "com.android.camera";
String mClass = ".CropImage";
intent.setComponent(new ComponentName(mPackage,mPackage+mClass));
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
It gives error :
Unable to find explicit activity class {com.android.camera/com.android.camera.CropImage}; have you declared this activity in your AndroidManifest.xml?
I tried to write in AndroidManifest.xml in my project ass well but still the same error.
Step #1: Add an <activity> element to your manifest pointing to com.android.camera.CropImage
Step #2: Use new Intent(this, com.android.camera.CropImage.class) to create your Intent
Step #3: There should be no step #3 AFAIK
Add activity like this in your android manifest file,
...
....
</activity>
<!-- Declare the bundled CropImage Activity -->
<activity android:name="com.android.camera.CropImage"/>
</application>
</manifest>
Documentation indeed helps :) link
does not compile. Indeed: even in 1.5, this api, getIntent(), is already listed as deprecated.
The error message I get complains that getIntent() does not return a String, but setCurrentTab() expects a string.
If I guess and change the line to read:
"tabHost.setCurrentTab(1); // was setCurrentTab(getIntent())",
then it compiles, builds, but does not run. I get the "stopped unexpectedly" error message from the emulator. I cannot even get Log.d to output, so it seems that it stops 'unexpectedly' very early.
So the first and main question is: what is the correct fix to "tabHost.setCurrentTab(getIntent())" in the final line of OnCreate() in http://developer.android.com/resources/tutorials/views/hello-tabwidget.html?
The second and simpler question is: did I guess right in replacing 'mTabHost' with tabHost in the one place where that occurs?
Here's the problems and fixes for that particular tutorial:
Step 2: When creating your activities, if you do not create them through the manifest then you'll need to add them to the manifest manually.
Add these lines to AndroidManifest.xml:
<activity android:name=".AlbumsActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar">
</activity>
<activity android:name=".ArtistsActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar">
</activity>
<activity android:name=".SongsActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar">
</activity>
Step 3: You are only instructed to create the ic_tab_artists.xml file. You'll need to create one for ic_tab_songs.xml and ic_tab_albums.xml as well. You can just duplicate the ic_tab_artists.xml (or change the HelloTabView.java tab specs to use the artists.xml file for each tab).
Step 4: The third to last line under /res/layout/main has a typo (a ; instead of a :)
android:padding="5dp" />
</LinearLayout>
</TabHost>
Step 6: There is a typo that uses calls mTabHost instead of tabHost. Change it.
As already cited the getIntent() function on the last line isn't appropriate. I just call the tab based on it's id. eg:
tabHost.setCurrentTabByTag("albums");
At the Informal Android Meetup, I was able to confirm that my first guess was in the ballpark: the line as printed in the tutorial really is wrong, it should be replaced with something like, "tabHost.setCurrentTab(0); // was setCurrentTab(getIntent())".
There was one other major omission I had to fix before I could get the HelloTabWidget Tutorial to run: Albums|Artists|SongsActivity all had to be added to the manifest, manifest.xml. Somehow, the tutorial instructions managed to omit mention of this requirement.