In the documentation for the Android manifest, there are multiple different ways to specify screenOrientation:
landscape
sensorLandscape added in API 9
userLandscape added in API 18
How can I specify userLandscape, but on older versions of Android, have it fallback to sensorLandscape, and on even older versions fall back to landscape? I couldn't find how to do this in the documentation.
I don't think that there's a way to implement the fallback mechanism in the manifest itself.
I would suggest that you specify one of { userLandscape, sensorLandscape, landscape } in the manifest. Then, check for the version at runtime and improvise.
Say, you decide to go with android:screenOrientation="userLandscape" in the manifest.
In your activity's onCreate(Bundle), before setting the content:
int sdkInt = Build.VERSION.SDK_INT;
// if we're running on some API level within [9, 18), use `sensorLandscape`
if (sdkInt >= Build.VERSION_CODES.GINGERBREAD /* 9 */
&& sdkInt < Build.VERSION_CODES.JELLY_BEAN_MR2 /* 18 */) {
setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else if (sdkInt < Build.VERSION_CODES.GINGERBREAD /* 9 */) {
setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
// API 18 or above - handled in manifest
setContentView(R.layout.whatever);
Hope that someone comes up with a better solution than this. This seems brute-force.
Edit:
Tried a different approach - from what I know (and I could be wrong here), enums such as userLandscape, sensorLandscape etc. won't change values. As they currently stand:
<attr name="screenOrientation">
<enum name="unspecified" value="-1" />
<enum name="landscape" value="0" />
<enum name="portrait" value="1" />
<enum name="user" value="2" />
<enum name="behind" value="3" />
<enum name="sensor" value="4" />
<enum name="nosensor" value="5" />
<enum name="sensorLandscape" value="6" />
<enum name="sensorPortrait" value="7" />
<enum name="reverseLandscape" value="8" />
<enum name="reversePortrait" value="9" />
<enum name="fullSensor" value="10" />
<enum name="userLandscape" value="11" />
<enum name="userPortrait" value="12" />
<enum name="fullUser" value="13" />
<enum name="locked" value="14" />
</attr>
So, if you were to define an integer such as:
<!-- `0` for `landscape` -- defined in values/integers.xml -->
<integer name="customScreenOrientation">0</integer>
<!-- `6` for `sensorLandscape` -- defined in values-v9/integers.xml -->
<integer name="customScreenOrientation">6</integer>
<!-- `11` for `userLandscape` -- defined in values-v18/integers.xml -->
<integer name="customScreenOrientation">11</integer>
You could then use #integer/customScreenOrientation as the value for android:screenOrientation in your activity's tag.
Needless to say its a hack at best. If someone could confirm the steady status of enum values for screenOrientation, this could be a viable workaround - preferable to including code from my earlier suggestion in multiple activities.
Yet another edit:
The second approach I mentioned earlier can be improved upon:
Instead of multiple integers.xml files, create 3 styles.xml files. I guess you already have one - values/styles.xml. Create values-v9/styles.xml & values-v18/styles.xml.
<!-- values/styles.xml -->
<style name="AppTheme" parent="#style/BaseTheme">
<item name="android:screenOrientation">landscape</item>
</style>
<!-- values-v9/styles.xml -->
<style name="AppTheme" parent="#style/BaseTheme">
<item name="android:screenOrientation">sensorLandscape</item>
</style>
<!-- values-v18/styles.xml -->
<style name="AppTheme" parent="#style/BaseTheme">
<item name="android:screenOrientation">userLandscape</item>
</style>
Following this, create values/integers.xml(one file) and define an integer customScreenOrientation:
<integer name="customScreenOrientation">?android:attr/screenOrientation</integer>
You activity tag will look like:
<activity
....
android:theme="#style/AppTheme"
android:screenOrientation="#integer/customScreenOrientation"/>
The advantage of this approach over the second one is that we get to use the enums in place of hard-coded values. Again, these two approaches are equivalent if enum-values are set in stone. If they do change, the second approach will fail while the third one keeps on going.
Related
So I am writing my own custom view, that has both a TextView and an EditText within it. What I am trying to do is let the user set a text style for each one individually, like this:
<declare-styleable name="InputRow">
<attr name="descriptionTextStyle" format="string" />
<attr name="valueTextStyle" format="string" />
</declare-styleable>
I thought this would work, so that in XML I could say:
app:descriptionTextStyle="bold"
app:valueTextStyle="italic"
However, the problem comes when I am trying to read from the typed array. I can get the string:
if(typedArray.hasValue(R.styleable.InputRow_descriptionTextStyle)) {
setDescriptionTextStyle(typedArray.getString(R.styleable.InputRow_descriptionTextStyle));
}
but when I want to call descriptionTextView.setTypeface(Typeface tf, int style) I need an integer value for the second parameter, which I don't have.
I can't change the style to be an int format, because then ="bold" would be invalid, so I'm at a loss for how to get the text style.
Thanks to the suggestion from pskink, I took a look at how Android defines the style:
<!-- Default text typeface style. -->
<attr name="textStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
<flag name="italic" value="2" />
</attr>
Given that, I was able to update my custom attribute accordingly:
<attr name="descriptionTextStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
<flag name="italic" value="2" />
</attr>
Then I was able to setup my item by calling app:descriptionTextStyle="bold" and in the class I call typedArray.getInt() and call the setTypeface() method as I said. Thanks for the help!
You can use the
public void setTypeface(Typeface tf);
method, it only requires a typeface parameter.
Also for converting string to typeface you can do something like this:
switch (typefaceString) {
case SANS:
tf = Typeface.SANS_SERIF;
break;
case SERIF:
tf = Typeface.SERIF;
break;
case MONOSPACE:
tf = Typeface.MONOSPACE;
break;
}
I have created a custom compound view inside a library application and everything was OK. When I add custom attributes to view, I always get default values. I followed this steps with only one difference: my view is in a library project.
/res/values/attrs.xml
<resources>
<declare-styleable name="DatePickerView">
<attr name="showToday" format="boolean" />
<attr name="calendar" format="enum">
<enum name="jalali" value="0" />
<enum name="gregorian" value="1" />
</attr>
</declare-styleable>
</resources>
Layout file that contains view:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:farayan="http://schemas.android.com/apk/lib/net.farayan.android.view"
...
<net.farayan.android.view.datepicker.DatePickerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
farayan:showToday="false"
farayan:calendar="gregorian"/>
...
Component's code:
int calendar;
boolean showToday;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePickerView, 0, 0);
try {
calendar = a.getInteger(R.styleable.DatePickerView_calendar, 0);
showToday = a.getBoolean(R.styleable.DatePickerView_showToday, true);
} finally {
a.recycle();
}
calendar and showToday are always 0 and true respectively. Any idea?
It looks like something is not right here:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:farayan="http://schemas.android.com/apk/lib/net.farayan.android.view"
What about change to:
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:farayan="http://schemas.android.com/apk/res/net.farayan.android.view"
net.farayan.android.view is your app root namespace.
update1
xmlns:farayan="http://schemas.android.com/apk/res/your_main_app_package"
Here is am example. It use a view defined in the library project.
If we add new compound view code and its attributesinside project, we should add this at the beginning of layout:
xmlns:custom="http://schemas.android.com/apk/res/your_main_app_package
and if new compound view is inside a library project linked to our peoject, we should add this:
xmlns:custom="http://schemas.android.com/apk/res-auto
Link: https://stackoverflow.com/a/10217752/1152549
I am trying to read attribute values from themes and styles which were designed for platforms that are newer than I am running my application on.
Please don't ask why. If you know anything about the libraries I write then you should already know that I like to push the capabilities of the platform :)
I am operating under the presumption that when Android styles are compiled the attribute constants are what is used for the keys and therefore should theoretically be able to be read on any platform somehow. This is what I have observed to be happening with layout XMLs in my other libraries with no trouble.
Here is a base test case which shows the problem. This should be compiled using Android 3.0+.
<resources>
<style name="Theme.BreakMe">
<item name="android:actionBarStyle">#style/Widget.BreakMe</item>
</style>
<style name="Widget.BreakMe" parent="android:Widget">
<item name="android:padding">20dp</item>
</style>
</resources>
The fact that this uses android:actionBarStyle specifically is irreleveant. All that should be understood is that its an attribute which was only available starting with Android 3.0.
Here are the way that I have tried to access these values thus far on platforms prior to Android 3.0.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Break Me"
style="?android:attr/actionBarStyle"
/>
and
<declare-styleable name="Whatever">
<item name="datStyle" format="reference" />
</declare-styleable>
<style name="Theme.BreakMe.Take2">
<item name="datStyle">?android:attr/actionBarSize</item>
</style>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Break Me"
style="?attr/datStyle"
/>
and
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarStyle, outValue, true);
and
int[] Theme = new int[] { android.R.attr.actionBarSize };
int Theme_actionBarSize = 0;
TypedArray a = context.obtainStyledAttributes(attrs, Theme);
int ref = a.getResourceId(Theme_actionBarSize, 0);
and
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, android.R.attr.actionBarStyle, 0);
All of them result in this error in LogCat:
E/ResourceType(5618): Style contains key with bad entry: 0x010102ce
The 0x010102ce constant is the attribute value of android.R.attr.actionBarStyle which seems to indicate the platform is rejecting the attribute before I can even get a chance to access its value.
I am looking for any other way to read attributes like this from the Theme. I'm fairly sure that once I've obtained the style reference I won't have trouble reading its attributes.
Is there any possible way to do this?
I am operating under the presumption that when Android styles are compiled the attribute constants are what is used for the keys and therefore should theoretically be able to be read on any platform somehow.
Possibly, though that is not how I am interpreting the C++ source code that raises the error you are seeing. Check out ResTable::Theme::applyStyle() in frameworks/base/libs/utils/ResourceTypes.cpp.
My interpretation is that Android has what amounts to an in-memory table of packages->types->possible entries:
numEntries = curPI->types[t].numEntries;
Your entry index is higher than the highest known entry:
if (e >= numEntries) {
LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
bag++;
continue;
}
It is possible that they handle this different for android versus other packages -- android uses known values at firmware build time (and your generated entry index is higher, because it is from a newer platform), non-android ones assume anything's valid.
If my guesswork is correct, what you want to do will not work. That being said, my C++ days are seriously in my rear-view mirror, so I may be misinterpreting what I'm seeing.
Perhaps I'm missing the end goal here, but I put together the following example that was able to read out all the attributes without issue on any 2.x device. The example was compiled against a 3.0 targetSdk.
styles.xml (Declare the styles and themes)
<resources>
<style name="Theme.NewFeatures" parent="android:Theme">
<item name="android:actionBarStyle">#style/Widget.MyActionBar</item>
</style>
<style name="Widget.MyActionBar" parent="android:Widget">
<item name="android:padding">20dp</item>
</style>
</resources>
attrs.xml (Declare the attribute groups you wish to obtain at runtime)
<resources>
<declare-styleable name="ActionBarNewFeatures">
<attr name="android:actionBarStyle" />
</declare-styleable>
<declare-styleable name="MyWidgetNewFeatures">
<attr name="android:padding" />
</declare-styleable>
</resources>
AndroidManifest.xml (Apply the custom theme)
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.NewFeatures" >
<activity
android:name=".SomeActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
SomeActivity.java (Go digging for attributes)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TypedArray a = obtainStyledAttributes(R.styleable.ActionBarNewFeatures);
//Get the style ID for the widget
int resid = a.getResourceId(R.styleable.ActionBarNewFeatures_android_actionBarStyle, -1);
a.recycle();
a = obtainStyledAttributes(resid, R.styleable.MyWidgetNewFeatures);
int padding = a.getDimensionPixelSize(R.styleable.MyWidgetNewFeatures_android_padding, -1);
a.recycle();
TextView tv = new TextView(this);
tv.setText(String.format("Padding will be %d px", padding));
setContentView(tv);
}
As long as I compile the example against 3.0 so it can resolved all the attribute names; on every 2.X device/emulator I have this will correctly read into the theme and then into the widget style to get the scaled padding dimension I had set.
Hope I didn't miss something big.
Probably, You must define a few themes. For old devices use folder res/values-v11/themes.xml. See section "Using Holo while supporting Android 2.x" in the http://android-developers.blogspot.com/2012/01/holo-everywhere.html
I've been searching for the answer for a while, but I can't find the same set of circumstances, so I turn to you for help...
I'm trying to use the google SDK (not the admob sdk) to put ads in my android app. When running the app in the emulator, the log messages that I see are:
03-25 22:35:17.457: INFO/Ads(853): adRequestUrlHtml: [ contains two <script> tags ]
03-25 22:35:21.028: INFO/Ads(853): Received ad url: [ big long url ]
Sometimes I get:
03-25 22:35:21.828: INFO/Ads(853): onFailedToReceiveAd(No ad to show.)
which perhaps I can understand, but I also get:
03-25 22:50:56.817: INFO/Ads(1084): onFailedToReceiveAd(A network error occurred.)
If I hit the "big long url" above in my desktop browser, I get an ad about 1/2 the time and blank the other 1/2. (Hello, Dish Network) I never get an error.
I can browse the web with the emulator's browser, so the network component is working.
The app has internet privileges.
I'm frustrated with the lack of usable sample code - I see a lot of people using the old admob SDK and a few code fragments of people using the google SDK, but not a soup-to-nuts example/tutorial.
I've commented out the rest of my code, to no avail. Here's the main chunk of code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AdView adView = new AdView(this, AdSize.BANNER, ADMOB_PUBLISHER_ID);
LinearLayout layout = (LinearLayout)findViewById(R.id.mainLayout);
layout.addView(adView);
AdRequest req = new AdRequest();
// req.setTesting(true);
adView.loadAd(req);
}
My manifest includes this:
<activity android:name="com.google.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation"/>
and
<uses-permission android:name="android.permission.INTERNET" />
My main.xml contains this layout for the page:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/yellow"
android:id="#+id/mainLayout"
>
admob support hasn't replied.
Can anyone help me or at least refer me to the perfect google sdk guide for admob noobs?
Thanks!
have you add attr.xml file???
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="com.google.ads.AdView">
<attr name="adSize">
<enum name="BANNER" value="1"/>
<enum name="IAB_MRECT" value="2"/>
<enum name="IAB_BANNER" value="3"/>
<enum name="IAB_LEADERBOARD" value="4"/>
</attr>
<attr name="adUnitId" format="string"/>
</declare-styleable>
</resources>
try adding this permission line to your AndroidManifest.xml file
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Friends, I meet the same problem today. I followed the whold google instruction. Finally, I got it. You can customize the request for call load. Like this:
AdRequest re = new AdRequest();
//re.setTesting(true);
re.setGender(AdRequest.Gender.FEMALE);
adview.loadAd(re);
You can try my example, I put my apk and source code here:
Add Google Admob in Android Application
I have an XML resource file:
<resources>
<section>
<category value="1" resourceId="#xml/categoryData1" />
<category value="2" resourceId="#xml/categoryData2" />
<category value="3" resourceId="#xml/categoryData3" />
</section>
</resources>
Using XmlPullParser, on the START_TAG, I can use:
int value = parser.getAttributeIntValue(null, "value", 0);
to get values 1, 2, 3...however:
int resourceId = parser.getAttributeIntValue(null, "resourceId", 0);
doesn't work...it just yields the default value 0, or whatever I change the default value (3rd parameter) to be...
Does anyone know what I am doing wrong or if this is possible?
well, if you look in your resourceId attribute, it does not seem to contain an int, does it? Or am I misreading you?
you should instead use getAttributeValue and cast it in the right Type.