Extend an external application Style/Theme - android

I want to define an android style that extends one defined in a different Application/package not imported as library.
From the definition of an xml reference to an android resource here:
#[<package_name>:]<resource_type>/<resource_name>
seems that is possible to specify an external where the resource is defined ( as used to reference system resource #android:string/name )
Now, i have my main app ( package: com.example.test ) that define an attribute and a theme like this:
<declare-styleable name="TestAttrs">
<attr name="testColor" format="color" />
</declare-styleable>
<style name="TestTheme" parent="#android:style/Theme">
<item name="testColor">#FFFF0000</item>
</style>
if in a second, different app I try to use the previous package to define a style using the syntax shown above I get an error saying that the resouce can't be found.
<style name="SubTheme" parent="#com.example.test:style/TestTheme">
<item name="com.example.test:testColor">#FF00FF00</item>
</style>
is it possible to tell the compiler where to look for the package?
do i have to define my initial style/attributes as shared?

Did you declare the namespace:
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:com.example.test="...external resource's namespace">

package_name does not refer to external applications on the device, but other library-project packages you are building against (each have their own resource table, which is then merged).
To access private resources in external applications you can use PackageManager.getResourcesForApplication() or expose a ContentProvider and do it yourself.

Related

How would I implement a library styling system similar to the one in the cast SDK?

The Google Cast SDK allows custom styling.
For example, to style the cast mini controller (which is part of the cast SDK), you would put this in your app theme:
<item name="castMiniControllerStyle">#style/CustomCastMiniController</item>
And then you'd implement a CustomCastMiniController style, overriding any attributes that you'd like:
<style name="CustomCastMiniController" parent="CastMiniController">
<item name="castBackground">#FFFFFF</item>
</style>
tl;dr How would I implement a library styling system similar to the one in the cast SDK?
More specific questions:
Where would castMiniControllerStyle be defined? I'm guessing the cast SDK would provide that in its attrs.xml file. Something like:
<attr name="castMiniControllerStyle" format="reference" />
How does that attribute get used? Does the cast mini controller layout have an android:theme="?castMiniControllerStyle" on the root layout item?
How do you associate castMiniControllerStyle with an internal library style? I can create a theme for my library and do something like:
<style name="MyLibraryTheme">
<item name="castMiniControllerStyle">#style/CastMiniController<item>
</style>
But question #2 is already setting the theme to ?castMiniControllerStyle. So where do I apply MyLibraryTheme?

Declare attributes of library module which can be modified by app

I am trying to create Android library module (API 21+) for my application, which will implement some of the business logic shared across various applications.
The issue is that I want to declare attributes in this library module, for which I will be able to set values in app modules of aforementioned projects.
The funny thing is, that my current solution works on emulator but not on physical devices.
Here is how I have it now (simplified, irrelevant parts omitted):
Library's attrs.xml:
<resources>
<attr name="lib_Background" format="reference"/>
<attr name="lib_Logo" format="reference"/>
</resources>
Applications styles.xml:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="lib_Background">#drawable/back</item>
<item name="lib_Logo">#drawable/logo</item>
</style>
It does not matter whether I try to access these resources from xml of library's layout like this:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="?attr/lib_Background"
android:scaleType="centerCrop"/>
or programatically like this:
fun Context.getDrawableFromAttributes(idOfAttribute: Int): Drawable? {
val a = this.theme.obtainStyledAttributes(intArrayOf(idOfAttribute))
val resourceId = a.getResourceId(0, 0)
a.recycle()
return this.resources.getDrawable(resourceId, this.theme)
}
Still I have this image properly loaded on emulator, but "null" on physical device.
Is there some better or correct way how to achieve this?
I have kinda forgot about this question.
The issue was that I have used broken PNG for one particular density which caused it to be null. So it was not and error in implementation at all and this approach is absolutely valid.

What is "android:" prefix mean in android framework-res module

I copy the this code from the styles.xml file in framework-res module
<style name="Theme">
<item name="colorForeground">#android:color/bright_foreground_dark</item>
<item name="colorForegroundInverse">#android:color/bright_foreground_dark_inverse</item>
<item name="colorBackground">#android:color/background_dark</item>
.
<style name="Theme.Black">
<item name="android:windowBackground">#android:color/black</item>
<item name="android:colorBackground">#android:color/black</item>
</style>
As you see, they all have a attribute name which's value is windowBackground. But the formar has a android: and the latter doesn't. Is it really necessary to write a android: prefix in android framework?
Found this to be an interesting question and tried exploring to find the answer.. This is what I found..
from: http://developer.android.com/guide/topics/resources/style-resource.html
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style
name="style_name"
parent="#[package:]style/style_to_inherit">
<item
name="[package:]style_property_name"
>style_value</item>
</style>
</resources>
item - Defines a single property for the style. Must be a child of a element.
attributes:
name
Attribute resource. Required. The name of the style property to be defined, with a package prefix if necessary (for example android:textColor).
from: http://developer.android.com/guide/topics/manifest/manifest-intro.html
Resource values
Some attributes have values that can be displayed to users — for example, a label and an icon for an activity. The values of these attributes should be localized and therefore set from a resource or theme. Resource values are expressed in the following format,
#[package:]type:name
where the package name can be omitted if the resource is in the same package as the application, type is a type of resource — such as "string" or "drawable" — and name is the name that identifies the specific resource. For example:
Values from a theme are expressed in a similar manner, but with an initial '?' rather than '#':
?[package:]type:name
And finally, I tried giving the attributes without android:, and it threw an exception, though it compiled successfully.
Accessing Platform Resources
Android contains a number of standard resources, such as styles, themes, and layouts. To access these resource, qualify your resource reference with the android package name. For example, Android provides a layout resource you can use for list items in a ListAdapter:
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myarray));
In this example, simple_list_item_1 is a layout resource defined by the platform for items in a ListView. You can use this instead of creating your own layout for list items. (For more about using ListView, see the List View Tutorial.)

Is it possible to add a custom property into a style in an android resource?

I'm a using a view flow component into my project, which allows the dev to override some attributes, like that :
<org.taptwo.android.widget.TitleFlowIndicator
...
app:footerTriangleHeight="0dip"
... />
I am reusing this component into several layouts, and I would like to put the properties into a style.
But when I'm doing this, the parser says Error: No resource found that matches the given name: attr 'app:footerTriangleHeight', even if I add the namespace in the styles file.
Is there a way to do that in android ?
Thanks.
Android Application
If you are not using Android Libraries, then here is what you can do:
Define custom styleable attribute (I guess you've already done that).
Do not use your namespace prefix in style items (namespace defaults to current app's namespace).
Example:
In attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="testAttr" format="string"/>
</resources>
In styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TestStyle" >
<item name="testAttr">asdf</item>
</style>
</resources>
Android Library
If custom attribute comes from Android Library, you can still use described approach. It theoretically should work, because Android Library's namespace is the same as application's (from aapt tool perspective during the build). But I haven't test this myself.
If you're specifying namespace, it will show error. As far as I know, styles do not support xml namespaces. So this will fail:
In styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:app="http://schemas.android.com/apk/res/app.package.name">
<style name="TestStyle" >
<item name="app:testAttr">asdf</item>
</style>
</resources>
Parser automatically defaults to current app's AndroidManifest namespace, though you can not specify this namespace explicitly.
You can define the style in terms of your namespace, i've used it myself
i.e
<style name="whatever">
<item name="YourPackage.YourSubPackage:parametername">#drawable_or_anything/bla</item>
</style>

Custom attrs parameter used in styles.xml

I have a set of custom Android layout parameters defined in attrs.xml. Now I would like to use some tags in my styles.xml file.
At the moment I get this error:
error: Error: No resource found that matches the given name: attr 'custom:tag'
I have tried declaring custom XML namespace as follows:
<resources
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.my.project"
>
hoping, that the same logic used in every layout declaration can be applied here, but with no success.
The XML namespace mechanism is used to namespace tags and attributes. When you define a style like this:
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.my.project">
<style name="my_style"> <item name="custom:tag">some_value</item> </style>
</resources>
you are trying to apply XML namespacing to an attribute value, which won't work. In this case, you should specify the package name directly, like this:
<style name="my_style"> <item name="com.my.project:tag">some_value</item> </style>
Now Android will be able to resolve where the attribute is defined.
The accepted solution did not work for me, but it shed some light upon the situation.
The custom attributes are resolved and can be referenced in a global project's package name, like "com.ltst.project". Even if you have multiple modules (with the same base package name) the resources would be resolved in a project's package name.
So for me it was enough to just omit any prefixes for custom attributes in a style.
Custom attribute:
<declare-styleable name="SampleView">
<attr name="sample_color" format="reference" />
</declare-styleable>
Style:
<style name="SampleStyle">
<item name="sample_color">#color/sample_color</item>
</style>
You can use the link
xmlns: app = "http://schemas.android.com/apk/res-auto
and define the prefix for each tag as app

Categories

Resources