Showing preview only (266K chars total). Download the full file or copy to clipboard to get everything.
Repository: tvbarthel/IntentShare
Branch: master
Commit: 340b9ba55515
Files: 82
Total size: 240.4 KB
Directory structure:
gitextract_wcsb18mc/
├── .gitignore
├── README.md
├── build.gradle
├── config/
│ ├── quality/
│ │ ├── checkstyle/
│ │ │ ├── checkstyle.xml
│ │ │ └── suppressions.xml
│ │ ├── findbugs/
│ │ │ └── findbugs-filter.xml
│ │ ├── lint/
│ │ │ └── lint.xml
│ │ └── pmd/
│ │ └── pmd-ruleset.xml
│ └── quality.gradle
├── glide-loader/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/
│ └── fr/
│ └── tvbarthel/
│ └── intentshare/
│ └── loader/
│ └── glide/
│ └── GlideIconLoader.java
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── fr/
│ │ └── tvbarthel/
│ │ └── intentshare/
│ │ └── ApplicationTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── fr/
│ │ │ └── tvbarthel/
│ │ │ └── intentshare/
│ │ │ ├── AsyncIconLoader.java
│ │ │ ├── BottomRecyclerView.java
│ │ │ ├── IconLoader.java
│ │ │ ├── IntentShare.java
│ │ │ ├── IntentShareListener.java
│ │ │ ├── LayoutManagerFactory.java
│ │ │ ├── StyledAttributesUtils.java
│ │ │ ├── TargetActivity.java
│ │ │ ├── TargetActivityAdapter.java
│ │ │ ├── TargetActivityComparatorProvider.java
│ │ │ ├── TargetActivityHeaderView.java
│ │ │ ├── TargetActivityManager.java
│ │ │ ├── TargetActivityView.java
│ │ │ └── TargetChooserActivity.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── isl_activity_target_chooser.xml
│ │ │ └── isl_target_activity_view.xml
│ │ ├── layout-v23/
│ │ │ └── isl_target_activity_view.xml
│ │ ├── values/
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── public.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-v19/
│ │ │ └── styles.xml
│ │ └── values-v23/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ └── fr/
│ └── tvbarthel/
│ └── intentshare/
│ └── IntentShareTest.java
├── picasso-loader/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/
│ └── fr/
│ └── tvbarthel/
│ └── intentshare/
│ └── loader/
│ └── picasso/
│ └── PicassoIconLoader.java
├── sample/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── fr/
│ │ └── tvbarthel/
│ │ └── intentsharesample/
│ │ └── ApplicationTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── fr/
│ │ │ └── tvbarthel/
│ │ │ └── intentsharesample/
│ │ │ ├── Adapter.java
│ │ │ ├── ExtraProviderDialogFragment.java
│ │ │ ├── ExtraProviderWrapper.java
│ │ │ ├── ExtraProviderWrapperView.java
│ │ │ ├── FooterView.java
│ │ │ ├── HeaderView.java
│ │ │ ├── MainActivity.java
│ │ │ ├── SharingFileProvider.java
│ │ │ └── SocialTargetActivityComparatorProvider.java
│ │ └── res/
│ │ ├── anim/
│ │ │ └── wiggle.xml
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ ├── extra_provider_view.xml
│ │ │ ├── footer_view.xml
│ │ │ ├── fragment_dialog_extra_provider.xml
│ │ │ └── header_view.xml
│ │ ├── menu/
│ │ │ └── activity_sample_menu.xml
│ │ ├── values/
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-w820dp/
│ │ │ └── dimens.xml
│ │ └── xml/
│ │ └── file_provider_paths.xml
│ └── test/
│ └── java/
│ └── fr/
│ └── tvbarthel/
│ └── intentsharesample/
│ └── ExampleUnitTest.java
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io
### Android ###
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
/*/build/
gradle.properties
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
.DS_Store
# fabric
fabric.properties
================================================
FILE: README.md
================================================
IntentShare
==================
[](http://search.maven.org/#search%7Cga%7C1%7Cintentshare)
[](http://android-arsenal.com/details/1/3551)
This project is a light open-source library that improves the sharing experience on Android.
* [Motivations](#motivations)
* [Gradle dependency](#gradle-dependency)
* [Sample app](#sample-app)
* [Usage](#usage)
* [Simple usage](#simple-usage)
* [Dialog label](#dialog-label)
* [Image](#image)
* [Extra Provider](#extra-provider)
* [Build-in extra provider](#build-in-extra-provider)
* [Custom extra provider](#custom-extra-provider)
* [Listener](#listener)
* [Icon Loader](#icon-loader)
* [Picasso](#picasso)
* [Glide](#glide)
* [Custom icon loader](#custom-icon-loader)
* [Comparator Provider](#comparator-provider)
* [Release Note](#release-note)
* [What's next](#whats-next)
* [Contributing](#contributing)
* [License](#license)
* [Special Thanks](#special-thanks-to-)
Motivations
=======
Nowadays, sharing content is part of our daily life. Unfortunately, the Android framework tools do not provide a sharing experience which reaches all of our expectations. We decided to implement our own tool, IntentShare, that might improve the user experience of a sharing action by :
* providing different extras according to the chosen target activity in order to take advantages of each target's specificities.
* providing an easy way to track the selected target activities in order to improve/adapt the extras for a specific target.
* providing a sorted target activity list based on the context of your app in order to take advantages of how people use it.
Find more about our motivations [here](http://tvbarthel.fr/IntentShare/).
# Sample app
[Sample app available on the PlayStore](https://play.google.com/store/apps/details?id=fr.tvbarthel.intentsharesample)
# Gradle dependency
available on jcenter.
```groovy
compile 'fr.tvbarthel.intentshare:library:0.0.4'
```
dependencies
```groovy
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:recyclerview-v7:25.0.0'
```
# Usage
## Simple usage
```java
IntentShare.with(context)
.text("Default text you would like to share.")
.deliver();
```
## Dialog label
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.deliver();
```
## Image
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.image(Uri.parse("content://com.example.test.fileprovider/data/img.png"))
.deliver();
```
# Extra Provider
An extra provider can specify shared content for a given target activity.
## Build-in extra provider
### Facebook
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.image(Uri.parse("content://com.example.test.fileprovider/data/img.png"))
.facebookBody(Uri.parse("http://tvbarthel.fr"))
.deliver();
```
### Twitter
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.image(Uri.parse("content://com.example.test.fileprovider/data/img.png"))
.twitterBody("Tweet can only have 140 char!")
.deliver();
```
### Mail clients
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.image(Uri.parse("content://com.example.test.fileprovider/data/img.png"))
.mailSubject("Mail subject.")
.mailBody("Extended text you would like to share in mail body.")
.deliver();
```
## Custom extra provider
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.image(Uri.parse("content://com.example.test.fileprovider/data/img.png"))
.addExtraProvider(
new IntentShare.ExtraProvider("com.google.android.gm")
.disableText()
.overrideSubject("Gmail subject, no mail body.")
.disableImage()
)
.deliver();
```
By default, an ExtraProvider will copy the default shared content.
Replace default shared content :
```java
/**
* Provide a specific text for the linked package name.
*
* @param text text which will be used as {@link android.content.Intent#EXTRA_TEXT}
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider overrideText(String text);
/**
* Provide a specific subject for the linked package name.
*
* @param subject subject which will be used as {@link android.content.Intent#EXTRA_SUBJECT}
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider overrideSubject(String subject);
/**
* Provide a specific image for the linked package name.
*
* @param image image which will be used as {@link android.content.Intent#EXTRA_STREAM}
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider overrideImage(Uri image);
```
Avoid copying default shared content without overriding:
```java
/**
* Disable the extra {@link android.content.Intent#EXTRA_TEXT} for the linked package
* to avoid a copy from the default {@link IntentShare} text.
*
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider disableText();
/**
* Disable the extra {@link android.content.Intent#EXTRA_SUBJECT} for the linked package
* to avoid a copy from the default {@link IntentShare} subject.
*
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider disableSubject();
/**
* Disable the extra {@link android.content.Intent#EXTRA_STREAM} for the linked package
* to avoid a copy from the default {@link IntentShare} image.
*
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider disableImage();
```
# Listener
```java
intentShareListener = new IntentShareListener() {
@Override
public void onCompleted(String packageName) {
Log.d(TAG, "onCompleted : " + packageName);
}
@Override
public void onCanceled() {
Log.d(TAG, "onCanceled");
}
};
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.listener(intentShareListener)
.deliver();
```
# Icon loader
Default icon loader used to load target activities icons is based on AsyncTask.
## Picasso
If your are already using Picasso, you may want to consider using PicassoIconLoader:
```groovy
compile 'fr.tvbarthel.intentshare:picasso-loader:0.0.4'
```
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.iconLoader(new PicassoIconLoader())
.deliver();
```
## Glide
If your are already using Glide, you may want to consider using GlideIconLoader:
```groovy
compile 'fr.tvbarthel.intentshare:glide-loader:0.0.4'
```
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.iconLoader(new GlideIconLoader())
.deliver();
```
## Custom icon loader
Implement your own IconLoader:
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.iconLoader(new IconLoader() {
@Override
public void load(Uri iconUri, ImageView imageView) {
}
@Override
public void cancel(ImageView imageView) {
}
})
.deliver();
```
# Comparator provider
By default, target activities are sorted based on the recency of their selection from your app.
```java
/**
* Comparator used to sort {@link TargetActivity} based on the recency of their previous
* selection and their default order as fallback when they have never been selected.
* <p/>
* The ordering imposed by this comparator on a set of {@link TargetActivity}
* is not consistent with equals since c.compare(e1, e2)==0 has not the same boolean
* value as e1.equals(e2).
*/
public RecencyComparatorProvider() {
}
```
Instead of using the default comparator, you can implement your own comparator provider in order to customize the target activities order display to the user:
```java
/**
* ˙Interface which allow to define which comparator will be provided for sorting the
* target activity inside the {@link TargetChooserActivity}.
*/
public interface TargetActivityComparatorProvider extends Parcelable {
/**
* Provide the comparator used to sort {@link TargetActivity} displayed to the user.
*
* @return comparator used to sort {@link TargetActivity} displayed to the user.
*/
Comparator<TargetActivity> provideComparator();
}
```
```java
IntentShare.with(context)
.chooserTitle("Select a sharing target : ")
.text("Default text you would like to share.")
.comparatorProvider(customComparatorProvider)
.deliver();
```
An example from the sample can be found here : [SocialTargetActivityComparatorProvider.java](https://github.com/tvbarthel/IntentShare/blob/develop/sample/src/main/java/fr/tvbarthel/intentsharesample/SocialTargetActivityComparatorProvider.java)
# Release Note
* 0.0.4: min sdk set to 14.
* 0.0.3: Tweet length check no longer performed (see #39). `allowbackup` disable by default.
# What's next
* Providing easier way to share images.
* Removing dependencies on support libraries.
* Sample : implementing image selection for extra provider.
# Contributing
Contributions are very welcome (: You can contribute through GitHub by forking the repository and sending a pull request.
When submitting code, please make sure ./gradlew check succeed.
# License
```
Copyright (C) 2016 tvbarthel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
# Special Thanks to ...
Vincent Brison [https://github.com/vincentbrison](https://github.com/vincentbrison) , for his precious advice.
Stéphane Guérin [https://github.com/guerwan](https://github.com/guerwan) , for his helpful feedback.
Romain Zanon [https://github.com/romainz](https://github.com/romainz) , for his early day support.
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
buildToolsVersion = "25.0.0"
compileSdkVersion = 25
targetSdkVersion = 25
minSdkVersion = 14
versionCode = 4
versionName = "0.0.4"
}
================================================
FILE: config/quality/checkstyle/checkstyle.xml
================================================
<?xml version="1.0"?><!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.1//EN"
"http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
<module name="Checker">
<module name="FileLength">
<property name="max" value="700" />
<property name="fileExtensions" value="" />
</module>
<module name="SuppressionFilter">
<property name="file" value="${checkstyleSuppressionsPath}" />
</module>
<module name="TreeWalker">
<!-- See http://checkstyle.sf.net/config_sizes.html !-->
<!-- Checks for long lines. !-->
<module name="LineLength">
<property name="ignorePattern" value="^$" />
<property name="max" value="120" />
</module>
<!-- Checks the number of methods declared in each type. This includes the number of each scope !-->
<!-- (private, package, protected and public) as well as an overall total. !-->
<!-- See http://checkstyle.sourceforge.net/config_sizes.html#MethodCount !-->
<module name="MethodCount">
<property name="maxTotal" value="100" />
<property name="maxPrivate" value="100" />
<property name="maxPackage" value="100" />
<property name="maxProtected" value="100" />
<property name="maxPublic" value="100" />
</module>
<!-- Checks for long methods and constructors. !-->
<!-- See http://checkstyle.sf.net/config_sizes.html !-->
<module name="MethodLength">
<property name="max" value="120" />
<property name="countEmpty" value="true" />
<property name="tokens" value="METHOD_DEF, CTOR_DEF" />
</module>
<!-- Checks for the number of types declared at the outer (or root) level in a file. !-->
<!-- See http://checkstyle.sourceforge.net/config_sizes.html#OuterTypeNumber !-->
<module name="OuterTypeNumber">
<property name="max" value="1" />
</module>
<!-- Checks the number of parameters of a method or constructor. !-->
<!-- See http://checkstyle.sf.net/config_sizes.html !-->
<module name="ParameterNumber">
<!-- ReplacementSpan draw from AOSP is 9 parameters... !-->
<property name="max" value="9" />
<property name="tokens" value="METHOD_DEF, CTOR_DEF" />
</module>
</module>
<module name="TreeWalker">
<!-- Checks the padding of an empty for initializer. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="EmptyForInitializerPad">
<property name="option" value="nospace" />
</module>
<!-- Checks the padding of an empty for iterator. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="EmptyForIteratorPad">
<property name="option" value="nospace" />
</module>
<!-- Checks that the whitespace around the Generic tokens < and > is correct to the typical convention. !-->
<!-- See http://checkstyle.sourceforge.net/config_whitespace.html#GenericWhitespace !-->
<module name="GenericWhitespace" />
<!-- Checks the padding between the identifier of a method definition, !-->
<!-- constructor definition, method call, or constructor invocation; and the left parenthesis of the parameter list. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="MethodParamPad">
<property name="allowLineBreaks" value="false" />
<property name="option" value="nospace" />
<property name="tokens"
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF, SUPER_CTOR_CALL " />
</module>
<!-- Checks that there is no whitespace after a token. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="NoWhitespaceAfter">
<property name="allowLineBreaks" value="true" />
<property name="tokens"
value="ARRAY_INIT, BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS" />
</module>
<!-- Checks that there is no whitespace before a token. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="NoWhitespaceBefore">
<property name="allowLineBreaks" value="false" />
<property name="tokens" value="SEMI, POST_DEC, POST_INC" />
</module>
<!-- Checks the policy on how to wrap lines on operators. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="OperatorWrap">
<property name="option" value="nl" />
<property name="tokens" value="ASSIGN, BAND, BOR, BSR, BXOR, COLON, DIV,
EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF,
LOR, LT, MINUS, MOD, NOT_EQUAL,
PLUS, QUESTION, SL, SR, STAR" />
</module>
<!-- Checks the policy on the padding of parentheses. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="ParenPad">
<property name="option" value="nospace" />
<property name="tokens"
value="CTOR_CALL, LPAREN, METHOD_CALL, RPAREN, SUPER_CTOR_CALL" />
</module>
<!-- Checks the policy on the padding of parentheses for typecasts. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="TypecastParenPad">
<property name="option" value="nospace" />
<property name="tokens" value="TYPECAST, RPAREN" />
</module>
<!-- Checks that a token is followed by whitespace. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="WhitespaceAfter">
<property name="tokens" value="COMMA, SEMI, TYPECAST" />
</module>
<!-- Checks that a token is surrounded by whitespace. !-->
<!-- See http://checkstyle.sf.net/config_whitespace.html !-->
<module name="WhitespaceAround">
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN,
BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND,
LCURLY, LE, LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT,
MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN,
QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR, STAR_ASSIGN" />
<property name="allowEmptyConstructors" value="false" />
<property name="allowEmptyMethods" value="false" />
</module>
<!-- The following checks are actually not whitespace checks, but still fit here quite well. !-->
<!-- Checks that there is only one statement per line. !-->
<!-- See http://checkstyle.sourceforge.net/config_coding.html#OneStatementPerLine !-->
<module name="OneStatementPerLine" />
<!-- Checks that each variable declaration is in its own statement and on its own line. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="MultipleVariableDeclarations" />
</module>
<!-- Checks that there are no tabs in the source file !-->
<!-- http://checkstyle.sourceforge.net/config_whitespace.html#FileTabCharacter !-->
<module name="FileTabCharacter" />
<module name="TreeWalker">
<!-- Checks that the outer type name and the file name match. !-->
<!-- See http://checkstyle.sourceforge.net/config_misc.html#OuterTypeFilename !-->
<module name="OuterTypeFilename" />
<!-- Checks for class type parameter name naming conventions. !-->
<!-- See http://checkstyle.sourceforge.net/config_naming.html#ClassTypeParameterName !-->
<module name="ClassTypeParameterName">
<property name="format" value="^[A-Z]$" />
</module>
<!-- Checks for constant name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="ConstantName">
<property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$" />
<property name="applyToPublic" value="true" />
<property name="applyToProtected" value="true" />
<property name="applyToPackage" value="true" />
<property name="applyToPrivate" value="true" />
</module>
<!-- Checks for local final variable name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="LocalFinalVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
<property name="tokens" value="VARIABLE_DEF, PARAMETER_DEF" />
</module>
<!-- Checks for local variable name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="LocalVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
<property name="tokens" value="VARIABLE_DEF, PARAMETER_DEF" />
</module>
<!-- Checks for member variable name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="MemberName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
<property name="applyToPublic" value="true" />
<property name="applyToProtected" value="true" />
<property name="applyToPackage" value="true" />
<property name="applyToPrivate" value="true" />
</module>
<!-- Checks for method name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="MethodName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
</module>
<!-- Checks for method type parameter name naming conventions. !-->
<!-- See http://checkstyle.sourceforge.net/config_naming.html#MethodTypeParameterName !-->
<module name="MethodTypeParameterName">
<property name="format" value="^[A-Z]$" />
</module>
<!-- Checks for package name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="PackageName">
<property name="format" value="^[a-z][a-z0-9]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*$" />
</module>
<!-- Checks for parameter name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="ParameterName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
</module>
<!-- Checks for static variable name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="StaticVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
<property name="applyToPublic" value="true" />
<property name="applyToProtected" value="true" />
<property name="applyToPackage" value="true" />
<property name="applyToPrivate" value="true" />
</module>
<!-- Checks for type name naming conventions. !-->
<!-- See http://checkstyle.sf.net/config_naming.html !-->
<module name="TypeName">
<property name="format" value="^[A-Z][a-zA-Z0-9]*$" />
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF" />
<property name="applyToPublic" value="true" />
<property name="applyToProtected" value="true" />
<property name="applyToPackage" value="true" />
<property name="applyToPrivate" value="true" />
</module>
</module>
<module name="TreeWalker">
<!-- Validates Javadoc comments to help ensure they are well formed. !-->
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocStyle !-->
<module name="JavadocStyle">
<property name="scope" value="private" />
<!--
<property name="excludeScope" value=""/>
!-->
<property name="checkFirstSentence" value="false" />
<property name="endOfSentenceFormat" value="([.?!][ \t\n\r\f<])|([.?!]$)" />
<property name="checkEmptyJavadoc" value="false" />
<property name="checkHtml" value="true" />
<property name="tokens"
value="INTERFACE_DEF, CLASS_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF" />
</module>
<!-- Checks Javadoc comments for class and interface definitions. !-->
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocType !-->
<module name="JavadocType">
<property name="scope" value="package" />
<!--
<property name="excludeScope" value=""/>
!-->
<!--<property name="authorFormat" value=""/>!-->
<!--<property name="versionFormat" value=""/>!-->
<property name="allowMissingParamTags" value="false" />
<property name="allowUnknownTags" value="false" />
<property name="tokens" value="INTERFACE_DEF, CLASS_DEF" />
</module>
<!-- Checks to ensure that the javadoc tags exist (if required) !-->
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocMethod !-->
<module name="JavadocMethod">
<property name="scope" value="package" />
<!--
<property name="excludeScope" value=""/>
!-->
<property name="allowUndeclaredRTE" value="false" />
<property name="allowThrowsTagsForSubclasses" value="false" />
<property name="allowMissingParamTags" value="false" />
<property name="allowMissingThrowsTags" value="false" />
<property name="allowMissingReturnTag" value="false" />
<property name="allowMissingJavadoc" value="false" />
<property name="allowMissingPropertyJavadoc" value="false" />
<property name="logLoadErrors" value="true" />
<property name="suppressLoadErrors" value="false" />
<property name="tokens" value="METHOD_DEF, CTOR_DEF" />
</module>
<!-- Checks that variables have Javadoc comments. !-->
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocVariable !-->
<module name="JavadocVariable">
<property name="scope" value="package" />
<!--
<property name="excludeScope" value=""/>
!-->
</module>
</module>
<module name="TreeWalker">
<!-- Ensure a class has a package declaration. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="PackageDeclaration">
<property name="ignoreDirectoryName" value="true" />
</module>
</module>
<module name="TreeWalker">
<!-- Checks visibility of class members. !-->
<!-- See http://checkstyle.sf.net/config_design.html !-->
<module name="VisibilityModifier">
<property name="packageAllowed" value="true" />
<property name="protectedAllowed" value="true" />
<property name="publicMemberPattern" value="^serialVersionUID$" />
</module>
<!-- Checks that classes (except abtract one) define a ctor and don't rely on the default one. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<!--<module name="MissingCtor"/>!-->
<!-- Make sure that utility classes (classes that contain only static methods) do not have a public constructor. !-->
<!-- See http://checkstyle.sf.net/config_design.html !-->
<module name="HideUtilityClassConstructor" />
</module>
<module name="TreeWalker">
<!-- Checks that the order of modifiers conforms to the suggestions in the Java Language specification, !-->
<!-- sections 8.1.1, 8.3.1 and 8.4.3. !-->
<!-- See http://checkstyle.sf.net/config_modifiers.html !-->
<module name="ModifierOrder" />
<!-- Checks that there are no redundant modifiers. !-->
<!-- See http://checkstyle.sf.net/config_modifiers.html
<module name="RedundantModifier">
<property name="tokens" value="METHOD_DEF, VARIABLE_DEF, ANNOTATION_FIELD_DEF"/>
</module>
!-->
<!-- Checks that a class which has only private constructors is declared as final. !-->
<!-- See http://checkstyle.sf.net/config_design.html !-->
<module name="FinalClass" />
<!-- Check nested (internal) classes/interfaces are declared at the bottom of the class after all method and field declarations. !-->
<!-- See http://checkstyle.sourceforge.net/config_design.html#InnerTypeLast !-->
<module name="InnerTypeLast" />
<!-- Implements Bloch, Effective Java, Item 17 - Use Interfaces only to define types. !-->
<!-- See http://checkstyle.sf.net/config_design.html !-->
<module name="InterfaceIsType">
<property name="allowMarkerInterfaces" value="true" />
</module>
<!-- Restricts throws statements to a specified count. !-->
<!-- See http://checkstyle.sf.net/config_design.html !-->
<module name="ThrowsCount">
<property name="max" value="2" />
</module>
<!-- Checks that classes that define a covariant equals() method also override method equals(java.lang.Object). !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="CovariantEquals" />
<!-- Checks declaration order according to Code Conventions for the Java Programming Language. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="DeclarationOrder">
<property name="ignoreConstructors" value="false" />
<property name="ignoreMethods" value="false" />
<property name="ignoreModifiers" value="false" />
</module>
<!-- Check that the default is after all the cases in a switch statement. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="DefaultComesLast" />
<!-- Detects empty statements (standalone ;). !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="EmptyStatement" />
<!-- Catching java.lang.Exception, java.lang.Error or java.lang.RuntimeException is almost never acceptable. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="IllegalCatch">
<property name="illegalClassNames"
value="java.lang.Throwable, java.lang.RuntimeException" />
</module>
<!-- This check can be used to ensure that types are not declared to be thrown. !-->
<!-- Declaring to throw java.lang.Error or java.lang.RuntimeException is almost never acceptable. !-->
<!-- See http://checkstyle.sourceforge.net/config_coding.html#IllegalThrows !-->
<module name="IllegalThrows">
<property name="illegalClassNames"
value="java.lang.Throwable, java.lang.Error, java.lang.RuntimeException" />
</module>
<!-- Checks for assignments in subexpressions, such as in String s = Integer.toString(i = 2);. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="InnerAssignment">
<property name="tokens" value="ASSIGN, BAND_ASSIGN, BOR_ASSIGN, BSR_ASSIGN, BXOR_ASSIGN,
DIV_ASSIGN, MINUS_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, SL_ASSIGN,
SR_ASSIGN, STAR_ASSIGN" />
</module>
<!-- Checks that switch statement has "default" clause. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="MissingSwitchDefault" />
<!-- Check for ensuring that for loop control variables are not modified inside the for block. !-->
<!-- See http://checkstyle.sourceforge.net/config_coding.html#ModifiedControlVariable !-->
<module name="ModifiedControlVariable" />
<!-- Disallow assignment of parameters. !-->
<!-- See http://checkstyle.sf.net/config_coding.html !-->
<module name="ParameterAssignment" />
<!-- this got moved here from the import checks !-->
<!-- Checks for unused import statements. !-->
<!-- See http://checkstyle.sf.net/config_import.html !-->
<module name="UnusedImports" />
</module>
</module>
================================================
FILE: config/quality/checkstyle/suppressions.xml
================================================
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress checks="[a-zA-Z0-9]*" files="R.java"/>
<suppress checks="[a-zA-Z0-9]*" files="BuildConfig.java"/>
<suppress checks="[a-zA-Z0-9]*" files="Test"/>
</suppressions>
================================================
FILE: config/quality/findbugs/findbugs-filter.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<!-- http://stackoverflow.com/questions/7568579/eclipsefindbugs-exclude-filter-files-doesnt-work -->
<Match>
<Class name="~.*\.R\$.*" />
</Match>
<Match>
<Class name="~.*\.Manifest\$.*" />
</Match>
<!-- All bugs in test classes, except for JUnit-specific bugs -->
<Match>
<Class name="~.*\.*Test" />
<Not>
<Bug code="IJU" />
</Not>
</Match>
<Match>
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
</Match>
</FindBugsFilter>
================================================
FILE: config/quality/lint/lint.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<issue id="AdapterViewChildren" severity="ignore" />
<issue id="AllowBackup" severity="ignore" />
<issue id="AlwaysShowAction" severity="ignore" />
<issue id="ButtonCase" severity="ignore" />
<issue id="ButtonOrder" severity="ignore" />
<issue id="ButtonStyle" severity="ignore" />
<issue id="CommitPrefEdits" severity="ignore" />
<issue id="CommitTransaction" severity="ignore" />
<issue id="ContentDescription" severity="ignore" />
<issue id="CutPasteId" severity="ignore" />
<issue id="DalvikOverride" severity="ignore" />
<issue id="DefaultLocale" severity="ignore" />
<issue id="Deprecated" severity="ignore" />
<issue id="DeviceAdmin" severity="ignore" />
<issue id="DisableBaselineAlignment" severity="ignore" />
<issue id="DrawAllocation" severity="ignore" />
<issue id="DuplicateActivity" severity="ignore" />
<issue id="DuplicateDefinition" severity="ignore" />
<issue id="DuplicateIds" severity="ignore" />
<issue id="DuplicateIncludedIds" severity="ignore" />
<issue id="DuplicateUsesFeature" severity="ignore" />
<issue id="EnforceUTF8" severity="ignore" />
<issue id="ExportedContentProvider" severity="ignore" />
<issue id="ExportedReceiver" severity="ignore" />
<issue id="ExportedService" severity="ignore" />
<issue id="ExtraText" severity="ignore" />
<issue id="ExtraTranslation" severity="ignore" />
<issue id="FloatMath" severity="ignore" />
<issue id="GifUsage" severity="ignore" />
<issue id="GradleOverrides" severity="ignore" />
<issue id="GrantAllUris" severity="ignore" />
<issue id="GridLayout" severity="ignore" />
<issue id="HandlerLeak" severity="ignore" />
<issue id="HardcodedDebugMode" severity="ignore" />
<issue id="HardcodedText" severity="ignore" />
<issue id="IconColors" severity="ignore" />
<issue id="IconDensities" severity="error" />
<issue id="IconDipSize" severity="error" />
<issue id="IconDuplicates" severity="ignore" />
<issue id="IconDuplicatesConfig" severity="ignore" />
<issue id="IconExtension" severity="ignore" />
<issue id="IconLauncherShape" severity="ignore" />
<issue id="IconLocation" severity="ignore" />
<issue id="IconMissingDensityFolder" severity="ignore" />
<issue id="IconMixedNinePatch" severity="ignore" />
<issue id="IconNoDpi" severity="ignore" />
<issue id="IconXmlAndPng" severity="ignore" />
<issue id="IllegalResourceRef" severity="ignore" />
<issue id="InOrMmUsage" severity="ignore" />
<issue id="InconsistentArrays" severity="ignore" />
<issue id="InconsistentLayout" severity="ignore" />
<issue id="InefficientWeight" severity="ignore" />
<issue id="InlinedApi" severity="ignore" />
<issue id="InnerclassSeparator" severity="ignore" />
<issue id="Instantiatable" severity="ignore" />
<issue id="InvalidId" severity="ignore" />
<issue id="InvalidPackage" severity="ignore" />
<issue id="JavascriptInterface" severity="ignore" />
<issue id="LabelFor" severity="ignore" />
<issue id="LibraryCustomView" severity="ignore" />
<issue id="LocalSuppress" severity="ignore" />
<issue id="MangledCRLF" severity="ignore" />
<issue id="ManifestOrder" severity="ignore" />
<issue id="ManifestTypo" severity="ignore" />
<issue id="MenuTitle" severity="ignore" />
<issue id="MergeRootFrame" severity="ignore" />
<issue id="MissingApplicationIcon" severity="ignore" />
<issue id="MissingId" severity="ignore" />
<issue id="MissingPrefix" severity="ignore" />
<issue id="MissingQuantity" severity="ignore" />
<issue id="MissingRegistered" severity="ignore" />
<issue id="MissingSuperCall" severity="ignore" />
<issue id="MissingTranslation" severity="ignore" />
<issue id="MissingVersion" severity="ignore" />
<issue id="MockLocation" severity="ignore" />
<issue id="MultipleUsesSdk" severity="ignore" />
<issue id="NamespaceTypo" severity="ignore" />
<issue id="NestedScrolling" severity="ignore" />
<issue id="NestedWeights" severity="ignore" />
<issue id="NewApi" severity="ignore" />
<issue id="NotSibling" severity="ignore" />
<issue id="ObsoleteLayoutParam" severity="ignore" />
<issue id="OldTargetApi" severity="ignore" />
<issue id="OnClick" severity="ignore" />
<issue id="Orientation" severity="ignore" />
<issue id="Overdraw" severity="ignore" />
<issue id="Override" severity="ignore" />
<issue id="PackagedPrivateKey" severity="ignore" />
<issue id="ParcelCreator" severity="ignore" />
<issue id="PrivateResource" severity="ignore" />
<issue id="Proguard" severity="ignore" />
<issue id="ProguardSplit" severity="ignore" />
<issue id="ProtectedPermissions" severity="ignore" />
<issue id="PxUsage" severity="ignore" />
<issue id="Recycle" severity="ignore" />
<issue id="Registered" severity="ignore" />
<issue id="RequiredSize" severity="ignore" />
<issue id="ResAuto" severity="ignore" />
<issue id="ResourceAsColor" severity="ignore" />
<issue id="ScrollViewCount" severity="ignore" />
<issue id="ScrollViewSize" severity="ignore" />
<issue id="SdCardPath" severity="ignore" />
<issue id="SecureRandom" severity="ignore" />
<issue id="ServiceCast" severity="ignore" />
<issue id="SetJavaScriptEnabled" severity="ignore" />
<issue id="ShowToast" severity="ignore" />
<issue id="SimpleDateFormat" severity="ignore" />
<issue id="SmallSp" severity="ignore" />
<issue id="SpUsage" severity="ignore" />
<issue id="StateListReachable" severity="ignore" />
<issue id="StringFormatCount" severity="ignore" />
<issue id="StringFormatInvalid" severity="ignore" />
<issue id="StringFormatMatches" severity="ignore" />
<issue id="StyleCycle" severity="ignore" />
<issue id="Suspicious0dp" severity="ignore" />
<issue id="SuspiciousImport" severity="ignore" />
<issue id="TextFields" severity="ignore" />
<issue id="TextViewEdits" severity="ignore" />
<issue id="TooDeepLayout" severity="ignore" />
<issue id="TooManyViews" severity="ignore" />
<issue id="TrulyRandom" severity="ignore" />
<issue id="TypographyDashes" severity="ignore" />
<issue id="TypographyEllipsis" severity="ignore" />
<issue id="TypographyFractions" severity="ignore" />
<issue id="TypographyOther" severity="ignore" />
<issue id="Typos" severity="ignore" />
<issue id="UniquePermission" severity="ignore" />
<issue id="UnknownId" severity="ignore" />
<issue id="UnknownIdInLayout" severity="ignore" />
<issue id="UnlocalizedSms" severity="ignore" />
<issue id="UnusedNamespace" severity="ignore" />
<issue id="UnusedQuantity" severity="ignore" />
<issue id="UnusedResources" severity="ignore" />
<issue id="UseCheckPermission" severity="ignore" />
<issue id="UseCompoundDrawables" severity="ignore" />
<issue id="UseSparseArrays" severity="ignore" />
<issue id="UseValueOf" severity="ignore" />
<issue id="UselessLeaf" severity="ignore" />
<issue id="UselessParent" severity="ignore" />
<issue id="UsesMinSdkAttributes" severity="ignore" />
<issue id="ValidFragment" severity="ignore" />
<issue id="ViewConstructor" severity="ignore" />
<issue id="ViewTag" severity="ignore" />
<issue id="Wakelock" severity="ignore" />
<issue id="WorldReadableFiles" severity="ignore" />
<issue id="WorldWriteableFiles" severity="ignore" />
<issue id="WrongCall" severity="ignore" />
<issue id="WrongCase" severity="ignore" />
<issue id="WrongFolder" severity="ignore" />
<issue id="WrongManifestParent" severity="ignore" />
<issue id="WrongViewCast" severity="ignore" />
</lint>
================================================
FILE: config/quality/pmd/pmd-ruleset.xml
================================================
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Android Application Rules"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>Custom ruleset for Android application</description>
<exclude-pattern>.*/R.java</exclude-pattern>
<exclude-pattern>.*/gen/.*</exclude-pattern>
<!-- exclude test files !-->
<exclude-pattern>.*Test.java</exclude-pattern>
<rule ref="rulesets/java/android.xml"/>
<rule ref="rulesets/java/clone.xml" />
<rule ref="rulesets/java/finalizers.xml" />
<rule ref="rulesets/java/imports.xml" />
<rule ref="rulesets/java/logging-java.xml" />
<rule ref="rulesets/java/braces.xml" />
<rule ref="rulesets/java/strings.xml">
<exclude name="AvoidDuplicateLiterals" />
<exclude name="AvoidStringBufferField"/>
</rule>
<rule ref="rulesets/java/basic.xml" >
<exclude name="CollapsibleIfStatements" />
<exclude name="AvoidBranchingStatementAsLastInLoop" />
</rule>
<rule ref="rulesets/java/naming.xml">
<exclude name="AbstractNaming" />
<exclude name="LongVariable" />
<exclude name="ShortMethodName" />
<exclude name="ShortVariable" />
<exclude name="VariableNamingConventions" />
<exclude name="ShortClassName" />
<exclude name="AvoidFieldNameMatchingMethodName" />
</rule>
</ruleset>
================================================
FILE: config/quality.gradle
================================================
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'
// Add checkstyle, findbugs, pmd and lint to the check task.
check.dependsOn 'checkstyle', 'findbugs', 'pmd', 'lint'
task checkstyle(type: Checkstyle) {
configFile file("${project.rootDir}/config/quality/checkstyle/checkstyle.xml")
configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/quality/checkstyle/suppressions.xml").absolutePath
source 'src'
include '**/*.java'
exclude '**/gen/**'
classpath = files()
}
task findbugs(type: FindBugs) {
ignoreFailures = false
effort = "max"
reportLevel = "high"
excludeFilter = new File("${project.rootDir}/config/quality/findbugs/findbugs-filter.xml")
classes = files("${project.rootDir}/library/build/intermediates/classes")
source 'src'
include '**/*.java'
exclude '**/gen/**'
reports {
xml.enabled = false
html.enabled = true
xml {
destination "$project.buildDir/reports/findbugs/findbugs.xml"
}
html {
destination "$project.buildDir/reports/findbugs/findbugs.html"
}
}
classpath = files()
}
task pmd(type: Pmd) {
ruleSetFiles = files("${project.rootDir}/config/quality/pmd/pmd-ruleset.xml")
ignoreFailures = false
ruleSets = []
source 'src'
include '**/*.java'
exclude '**/gen/**'
reports {
xml.enabled = false
html.enabled = true
xml {
destination "$project.buildDir/reports/pmd/pmd.xml"
}
html {
destination "$project.buildDir/reports/pmd/pmd.html"
}
}
}
android {
lintOptions {
abortOnError false
lintConfig file("${project.rootDir}/config/quality/lint/lint.xml")
// if true, generate an HTML report (with issue explanations, sourcecode, etc)
htmlReport true
// optional path to report (default will be lint-results.html in the builddir)
htmlOutput file("$project.buildDir/reports/lint/lint.html")
}
}
================================================
FILE: glide-loader/.gitignore
================================================
/build
================================================
FILE: glide-loader/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
apply from: '../config/quality.gradle'
group = 'fr.tvbarthel.intentshare'
version = rootProject.ext.versionName
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile project(':library')
compile 'com.github.bumptech.glide:glide:3.7.0'
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def bintrayUser = properties.getProperty('bintray.user')
def bintrayKey = properties.getProperty('bintray.apikey')
bintray {
user = bintrayUser
key = bintrayKey
configurations = ['archives'] //When uploading configuration files
dryRun = false //Whether to run this as dry-run, without deploying
publish = true //If version should be auto published after an upload
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'maven'
name = 'GlideLoader'
desc = 'Icon loader based on Glide for IntentShare library.'
websiteUrl = 'https://github.com/tvbarthel/IntentShare'
issueTrackerUrl = 'https://github.com/tvbarthel/IntentShare/issues'
vcsUrl = 'https://github.com/tvbarthel/IntentShare.git'
licenses = ['Apache-2.0']
labels = ['android', 'intent', 'sharing', 'share', 'glide']
publicDownloadNumbers = true
version {
gpg {
sign = true //Determines whether to GPG sign the files. The default is false
}
}
}
}
install {
repositories.mavenInstaller {
pom {
project {
packaging 'aar'
name 'GlideLoader'
url 'https://github.com/tvbarthel/IntentShare'
description 'Icon loader based on Glide for IntentShare library.'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'tbarthel-fr'
name 'Thomas Barthelemy'
email 'thomas.barthelemy.utc@gmail.com'
}
developer {
id 'vbarthel-fr'
name 'Vincent Barthelemy'
email 'vincent.barthelemy.perso@gmail.com'
}
}
scm {
connection 'https://github.com/tvbarthel/IntentShare.git'
developerConnection 'https://github.com/tvbarthel/IntentShare.git'
url 'https://github.com/tvbarthel/IntentShare'
}
}
}
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
failOnError = false
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
================================================
FILE: glide-loader/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/thomasbarthelemy/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: glide-loader/src/main/AndroidManifest.xml
================================================
<manifest package="fr.tvbarthel.intentshare.loader.glide">
<application />
</manifest>
================================================
FILE: glide-loader/src/main/java/fr/tvbarthel/intentshare/loader/glide/GlideIconLoader.java
================================================
package fr.tvbarthel.intentshare.loader.glide;
import android.net.Uri;
import android.os.Parcel;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import fr.tvbarthel.intentshare.IconLoader;
/**
* {@link fr.tvbarthel.intentshare.IconLoader} based on {@link com.bumptech.glide.Glide}
*/
public class GlideIconLoader implements IconLoader {
/**
* Parcelable
*/
public static final Creator<GlideIconLoader> CREATOR = new Creator<GlideIconLoader>() {
@Override
public GlideIconLoader createFromParcel(Parcel source) {
return new GlideIconLoader(source);
}
@Override
public GlideIconLoader[] newArray(int size) {
return new GlideIconLoader[size];
}
};
/**
* {@link fr.tvbarthel.intentshare.IconLoader} based on {@link com.bumptech.glide.Glide}
*/
public GlideIconLoader() {
}
/**
* {@link fr.tvbarthel.intentshare.IconLoader} based on {@link com.bumptech.glide.Glide}
*
* @param in parcel.
*/
protected GlideIconLoader(Parcel in) {
}
@Override
public void load(Uri iconUri, ImageView imageView) {
Glide.with(imageView.getContext())
.load(iconUri)
.fitCenter()
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.into(imageView);
}
@Override
public void cancel(ImageView imageView) {
Glide.clear(imageView);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Nov 11 10:54:16 CET 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: library/.gitignore
================================================
/build
================================================
FILE: library/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
apply from: '../config/quality.gradle'
group = 'fr.tvbarthel.intentshare'
version = rootProject.ext.versionName
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
resourcePrefix 'isl_'
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.9.5'
testCompile 'org.robolectric:robolectric:3.0'
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:recyclerview-v7:25.0.0'
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def bintrayUser = properties.getProperty('bintray.user')
def bintrayKey = properties.getProperty('bintray.apikey')
bintray {
user = bintrayUser
key = bintrayKey
configurations = ['archives'] //When uploading configuration files
dryRun = false //Whether to run this as dry-run, without deploying
publish = true //If version should be auto published after an upload
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'maven'
name = 'IntentShare'
desc = 'IntentShare is a light open-source library that improves the sharing experience of their Android applications.'
websiteUrl = 'https://github.com/tvbarthel/IntentShare'
issueTrackerUrl = 'https://github.com/tvbarthel/IntentShare/issues'
vcsUrl = 'https://github.com/tvbarthel/IntentShare.git'
licenses = ['Apache-2.0']
labels = ['android', 'intent', 'sharing', 'share']
publicDownloadNumbers = true
version {
gpg {
sign = true //Determines whether to GPG sign the files. The default is false
}
}
}
}
install {
repositories.mavenInstaller {
pom {
project {
packaging 'aar'
name 'IntentShare'
url 'https://github.com/tvbarthel/IntentShare'
description 'IntentShare is a light open-source library that improves the sharing experience of their Android applications.'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'tbarthel-fr'
name 'Thomas Barthelemy'
email 'thomas.barthelemy.utc@gmail.com'
}
developer {
id 'vbarthel-fr'
name 'Vincent Barthelemy'
email 'vincent.barthelemy.perso@gmail.com'
}
}
scm {
connection 'https://github.com/tvbarthel/IntentShare.git'
developerConnection 'https://github.com/tvbarthel/IntentShare.git'
url 'https://github.com/tvbarthel/IntentShare'
}
}
}
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
failOnError = false
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
================================================
FILE: library/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/thomas/Documents/android-sdk-linux/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: library/src/androidTest/java/fr/tvbarthel/intentshare/ApplicationTest.java
================================================
package fr.tvbarthel.intentshare;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: library/src/main/AndroidManifest.xml
================================================
<manifest package="fr.tvbarthel.intentshare"
xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".TargetChooserActivity"
android:theme="@style/IntentShareTheme" />
</application>
</manifest>
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/AsyncIconLoader.java
================================================
package fr.tvbarthel.intentshare;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Parcel;
import android.util.Log;
import android.util.SparseArray;
import android.widget.ImageView;
import java.util.HashMap;
import java.util.List;
/**
* Icon loader based on an {@link AsyncTask}.
* <p/>
* No cashing is performed for decoded {@link Bitmap}.
*/
class AsyncIconLoader implements IconLoader {
/**
* Parcelable.
*/
public static final Creator<AsyncIconLoader> CREATOR = new Creator<AsyncIconLoader>() {
@Override
public AsyncIconLoader createFromParcel(Parcel source) {
return new AsyncIconLoader(source);
}
@Override
public AsyncIconLoader[] newArray(int size) {
return new AsyncIconLoader[size];
}
};
private SparseArray<AsyncIconLoaderTask> task;
private HashMap<Uri, Bitmap> cachedIcons;
/**
* Icon loader based on an {@link AsyncTask}
* <p/>
* No cashing is performed for decoded {@link Bitmap}.
*
* @param in parcel.
*/
protected AsyncIconLoader(Parcel in) {
this();
}
/**
* Icon loader based on an {@link AsyncTask}
* <p/>
* No cashing is performed for decoded {@link Bitmap}.
*/
public AsyncIconLoader() {
task = new SparseArray<>();
cachedIcons = new HashMap<>();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
@Override
public void load(Uri iconUri, ImageView imageView) {
Bitmap bitmap = cachedIcons.get(iconUri);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
AsyncIconLoaderTask asyncIconLoaderTask
= new AsyncIconLoaderTask(iconUri, imageView, cachedIcons);
task.put(imageView.hashCode(), asyncIconLoaderTask);
asyncIconLoaderTask.execute();
}
}
@Override
public void cancel(ImageView imageView) {
int key = imageView.hashCode();
AsyncIconLoaderTask asyncIconLoaderTask = task.get(key);
if (asyncIconLoaderTask != null) {
asyncIconLoaderTask.cancel(true);
task.remove(key);
}
}
/**
* {@link AsyncTask} used to load an icon off the ui thread.
*/
private static final class AsyncIconLoaderTask extends AsyncTask<Void, Void, Bitmap> {
private static final String TAG = AsyncIconLoaderTask.class.getSimpleName();
private final ImageView imageTarget;
private final PackageManager packageManager;
private final String targetPackage;
private final HashMap<Uri, Bitmap> cachedIcons;
private final Uri uri;
private int iconResId;
private int targetSize;
/**
* {@link AsyncTask} used to load an icon off the ui thread.
*
* @param uri uri of the icon to load.
* @param imageView image view in which the icon should be loaded.
* @param cachedIcons list of bitmap to which the new decoded one will be added.
*/
public AsyncIconLoaderTask(Uri uri, ImageView imageView, HashMap<Uri, Bitmap> cachedIcons) {
packageManager = imageView.getContext().getPackageManager();
this.uri = uri;
targetPackage = uri.getAuthority();
iconResId = 0;
List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() != 1) {
Log.e(TAG, "Can't find the icon res id for : " + uri.toString());
} else {
try {
iconResId = Integer.parseInt(pathSegments.get(0));
} catch (NumberFormatException e) {
Log.e(TAG, "Can't parse the icon res id : " + pathSegments.get(0));
}
}
imageTarget = imageView;
targetSize = imageView.getContext().getResources()
.getDimensionPixelSize(R.dimen.isl_target_activity_view_icon_size);
this.cachedIcons = cachedIcons;
}
@Override
protected Bitmap doInBackground(Void... params) {
Resources resources;
try {
resources = packageManager.getResourcesForApplication(targetPackage);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Wrong package name, can't access to the resources : " + targetPackage);
return null;
}
if (isCancelled()) {
return null;
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
BitmapFactory.decodeResource(resources, iconResId, options);
if (isCancelled()) {
return null;
}
options.inSampleSize = calculateInSampleSize(options, targetSize, targetSize);
options.inJustDecodeBounds = false;
if (isCancelled()) {
return null;
} else {
return BitmapFactory.decodeResource(resources, iconResId, options);
}
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if (bitmap != null) {
imageTarget.setImageBitmap(bitmap);
cachedIcons.put(uri, bitmap);
} else {
Log.e(TAG, "Failed to load icon from uri : " + uri);
}
}
private int calculateInSampleSize(
BitmapFactory.Options options,
int reqWidth,
int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
if (reqWidth == 0 || reqHeight == 0) {
return 1;
} else {
int heightRatio = (int) Math.floor((float) height / (float) reqHeight);
int widthRatio = (int) Math.floor((float) width / (float) reqWidth);
return Math.min(heightRatio, widthRatio);
}
}
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/BottomRecyclerView.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Simple RecyclerView on which top padding could be assigned and enable touch on view under.
*/
class BottomRecyclerView extends RecyclerView {
/**
* Simple RecyclerView on which top padding could be assigned and enable touch on view under.
*
* @param context holding context.
*/
public BottomRecyclerView(Context context) {
super(context);
}
/**
* Simple RecyclerView on which top padding could be assigned and enable touch on view under.
*
* @param context holding context.
* @param attrs attr from xml.
*/
public BottomRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Simple RecyclerView on which top padding could be assigned and enable touch on view under.
*
* @param context holding context.
* @param attrs attr from xml.
* @param defStyleAttr style.
*/
public BottomRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = super.onTouchEvent(ev);
View child = getChildAt(0);
if (child == null || ev.getY() < child.getY()) {
handled = false;
}
return handled;
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/IconLoader.java
================================================
package fr.tvbarthel.intentshare;
import android.net.Uri;
import android.os.Parcelable;
import android.widget.ImageView;
/**
* Interface which define the contract of a loader used to load
* {@link TargetActivity} icons.
*/
public interface IconLoader extends Parcelable {
/**
* Called when the icon should be load into the imageView.
* <p/>
* See also : {@link IconLoader#cancel(ImageView)}
*
* @param iconUri uri of the icon to load.
* @param imageView image view in which the icon should be loaded.
*/
void load(Uri iconUri, ImageView imageView);
/**
* Called when the icon doesn't need to be loaded anymore.
* Should cancel any async loading started previously.
* <p/>
* See also : {@link IconLoader#load(Uri, ImageView)}
*
* @param imageView image view for which the async loading should be canceled.
*/
void cancel(ImageView imageView);
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/IntentShare.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
/**
* {@link IntentShare} is designed to enhance the sharing experience by allowing to share
* different content according to the application the user will choose to share with.
*/
public final class IntentShare implements Parcelable {
/**
* Parcelable.
*/
public static final Parcelable.Creator<IntentShare> CREATOR = new Parcelable.Creator<IntentShare>() {
public IntentShare createFromParcel(Parcel source) {
return new IntentShare(source);
}
public IntentShare[] newArray(int size) {
return new IntentShare[size];
}
};
/**
* Facebook package.
*/
public static final String FACEBOOK = "com.facebook.katana";
/**
* Twitter package.
*/
public static final String TWITTER = "com.twitter.android";
/**
* Text which will be shared by default.
*/
String text;
/**
* Uri of the image add as {@link android.content.Intent#EXTRA_STREAM}
*/
Uri imageUri;
/**
* Text used as mail body if the targeted application is a mail one.
*/
String mailBody;
/**
* Text used as mail subject if the targeted application is a mail one.
*/
String mailSubject;
/**
* Specific extra provider for some package.
*/
ArrayList<ExtraProvider> extraProviders;
/**
* Keep a track on package with a specific
* {@link fr.tvbarthel.intentshare.IntentShare.ExtraProvider} in order to warn the user when
* two provider are added for the same package.
*/
List<String> packageWithExtraProvider;
/**
* Icon loader used to load icons.
*/
IconLoader iconLoader;
/**
* Provide the comparator used to sort the target activities.
*/
TargetActivityComparatorProvider comparatorProvider;
/**
* Title that will be displayed in the chooser.
*/
String chooserTitle;
/**
* Context used to start the activity used to choose a target one.
*/
private Context context;
private IntentShareListener listener;
/**
* {@link IntentShare} is designed to enhance the sharing experience by allowing to share
* different content according to the application the user will choose to share with.
*
* @param context context used send the {@link android.content.Intent}
*/
private IntentShare(Context context) {
this.context = context;
extraProviders = new ArrayList<>();
packageWithExtraProvider = new ArrayList<>();
this.listener = null;
this.iconLoader = new AsyncIconLoader();
this.comparatorProvider = new TargetActivity.RecencyComparatorProvider();
this.chooserTitle = context.getString(R.string.isl_default_sharing_label);
}
/**
* {@link IntentShare} is designed to enhance the sharing experience by allowing to share
* different content according to the application the user will choose to share with.
*
* @param in parcel.
*/
protected IntentShare(Parcel in) {
this.text = in.readString();
this.imageUri = in.readParcelable(Uri.class.getClassLoader());
this.mailBody = in.readString();
this.mailSubject = in.readString();
this.extraProviders = in.createTypedArrayList(ExtraProvider.CREATOR);
this.iconLoader = in.readParcelable(IconLoader.class.getClassLoader());
this.comparatorProvider = in.readParcelable(TargetActivityComparatorProvider.class.getClassLoader());
this.chooserTitle = in.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.text);
dest.writeParcelable(this.imageUri, 0);
dest.writeString(this.mailBody);
dest.writeString(this.mailSubject);
dest.writeTypedList(this.extraProviders);
dest.writeParcelable(this.iconLoader, flags);
dest.writeParcelable(this.comparatorProvider, flags);
dest.writeString(this.chooserTitle);
}
/**
* {@link IntentShare} is designed to enhance the sharing experience by allowing to share
* different content according to the application the user will choose to share with.
*
* @param context context from which the sharing is initiated.
* @return new instance.
*/
@NonNull
public static IntentShare with(@NonNull Context context) {
return new IntentShare(context);
}
/**
* Title that will be displayed in the chooser.
* <p/>
* Will be displayed on a single line.
*
* @param title title that will be displayed in the chooser.
* @return current {@link IntentShare} for method chaining.
*/
public IntentShare chooserTitle(@NonNull String title) {
this.chooserTitle = title;
return this;
}
/**
* Set the {@link IconLoader} used to load target activities icon.
*
* @param iconLoader icon loader.
* @return current {@link IntentShare} for method chaining.
*/
public IntentShare iconLoader(@NonNull IconLoader iconLoader) {
this.iconLoader = iconLoader;
return this;
}
/**
* Provide a custom {@link java.util.Comparator} in order to sort the {@link TargetActivity}
* displayed to the user.
* <p/>
* By default, TargetActivities are sorted by the recentness of their selection. If it's the
* behaviour that you are looking for, don't use this method and let the default comparator
* bring the magic.
*
* @param comparatorProvider comparator used to sort the TargetActivities displayed to the user.
* Will override the default sorting by recentness.
* @return current {@link IntentShare} for method chaining.
*/
public IntentShare comparatorProvider(@NonNull TargetActivityComparatorProvider comparatorProvider) {
if (comparatorProvider == null) {
throw new NullPointerException("Custom comparator provider can't be null.");
}
this.comparatorProvider = comparatorProvider;
return this;
}
/**
* Text which will be shared.
* <p/>
* Will be used as {@link android.content.Intent#EXTRA_TEXT}
*
* @param text text to share.
* @return current {@link IntentShare} for method chaining.
*/
@NonNull
public IntentShare text(@NonNull String text) {
this.text = text;
return this;
}
/**
* Image which will be set as {@link android.content.Intent#EXTRA_STREAM} if the
* target application can handle it.
*
* @param imageUri Uri of the image.
* @return current {@link IntentShare} for method chaining.
*/
@NonNull
public IntentShare image(@NonNull Uri imageUri) {
String lastPathSegment = imageUri.getLastPathSegment();
if (!lastPathSegment.endsWith(".png") && !lastPathSegment.endsWith(".jpg")) {
throw new IllegalArgumentException("Invalid image uri : only .png and .jpg file supported : "
+ imageUri);
} else if (!"content".equals(imageUri.getScheme())) {
throw new IllegalArgumentException("Invalid image uri : only content scheme supported : "
+ imageUri);
} else {
this.imageUri = imageUri;
}
return this;
}
/**
* Text which will be shared by any application marked as mail client
* (application which can handle "message/rfc822").
* <p/>
* Override {@link IntentShare#text(String)} for every mail application.
*
* @param mailBody text set as text body for mail application.
* @return current {@link IntentShare} for method chaining.
*/
@NonNull
public IntentShare mailBody(@NonNull String mailBody) {
this.mailBody = mailBody;
return this;
}
/**
* Text which will be displayed inside the subject field of any application marked as mail
* client (applcation which can handle "message/rfc822").
* <p/>
* See also : {@link IntentShare#mailBody(String)}
*
* @param mailSubject subject of the mail.
* @return current {@link IntentShare} for method chaining.
*/
@NonNull
public IntentShare mailSubject(@NonNull String mailSubject) {
this.mailSubject = mailSubject;
return this;
}
/**
* Link which will be used as single shared content if target application is the facebook
* since facebook app don't handle {@link android.content.Intent#EXTRA_TEXT}
* <p/>
* Override {@link IntentShare#text(String)} for the Facebook application.
*
* @param link link to the content.
* @return current {@link IntentShare} for method chaining.
*/
@NonNull
public IntentShare facebookBody(@NonNull Uri link) {
String scheme = link.getScheme();
if (!"http".equals(scheme) && !"https".equals(scheme)) {
throw new IllegalArgumentException("Invalid facebook link : un handled scheme : "
+ scheme);
} else if (packageWithExtraProvider.contains(IntentShare.FACEBOOK)) {
throw new IllegalArgumentException("Facebook link can only be set once.");
} else {
packageWithExtraProvider.add(IntentShare.FACEBOOK);
extraProviders.add(
new ExtraProvider(IntentShare.FACEBOOK)
.overrideText(link.toString())
.disableImage()
.disableSubject()
);
}
return this;
}
/**
* Text which will be used as tweet body if target application is the Twitter one.
* <p/>
* Override {@link IntentShare#text(String)} for the Twitter application.
* <p>
* Note that length compliancy (140 char) isn't handle by the library anymore since
* tweet lenght can't be easily deduced from the text length directly.
* <p>
* Please refer to the following link if you want to ensure the length check on your side:
* https://blog.twitter.com/2016/doing-more-with-140-characters
*
* @param tweet tweet body.
* @return current {@link IntentShare} for method chaining.
*/
@NonNull
public IntentShare twitterBody(@NonNull String tweet) {
if (packageWithExtraProvider.contains(IntentShare.TWITTER)) {
throw new IllegalArgumentException("Twitter body can only be set once.");
} else {
packageWithExtraProvider.add(IntentShare.TWITTER);
extraProviders.add(
new ExtraProvider(TWITTER)
.overrideText(tweet)
);
}
return this;
}
/**
* Allow to set a listener to be notified on chosen target activity.
* <p/>
* Listener will be automatically unregister once a result is delivered.
*
* @param listener listener to register.
* @return current {@link IntentShare} for method chaining.
*/
public IntentShare listener(@NonNull IntentShareListener listener) {
this.listener = listener;
return this;
}
/**
* Allow to add a specific intent for a given
*
* @param extraProvider extra provider for a given package;
* @return current {@link IntentShare} for method chaining.
*/
public IntentShare addExtraProvider(@NonNull ExtraProvider extraProvider) {
if (extraProvider == null) {
throw new IllegalArgumentException("Extra provider can't be null");
} else if (packageWithExtraProvider.contains(extraProvider.packageName)) {
throw new IllegalArgumentException("Extra provider already provided for the package : "
+ extraProvider.packageName);
}
extraProviders.add(extraProvider);
return this;
}
/**
* Deliver the intent to the system.
* <p/>
* This will lead to the display of every applications that can handle the build intent.
* Target activity field will be then filled according to the params.
*/
public void deliver() {
if (this.listener != null) {
this.listener.register(context);
}
TargetChooserActivity.start(context, this);
}
/**
* Used to provide specific extras for a given package name
*/
public static class ExtraProvider implements Parcelable {
/**
* Parcelable.
*/
public static final Creator<ExtraProvider> CREATOR = new Creator<ExtraProvider>() {
@Override
public ExtraProvider createFromParcel(Parcel source) {
return new ExtraProvider(source);
}
@Override
public ExtraProvider[] newArray(int size) {
return new ExtraProvider[size];
}
};
/**
* Package for which specific extras must be provided.
*/
String packageName;
/**
* Specific text to provide.
*/
String overriddenText;
/**
* Specific mail subject to provide.
*/
String overriddenSubject;
/**
* Specific image to provide.
*/
Uri overriddenImage;
/**
* Used to know if default text must be removed.
*/
boolean textDisabled;
/**
* Used to know if default subject must be removed.
*/
boolean subjectDisabled;
/**
* Used to know if default image must be removed.
*/
boolean imageDisabled;
/**
* Used to provide specific extras for a given package name.
* <p/>
* By default, every extras are going to be copied from the {@link IntentShare}.
* <p/>
* To override extras :
* {@link ExtraProvider#overrideText(String)}
* {@link ExtraProvider#overrideSubject(String)}
* {@link ExtraProvider#overrideImage(Uri)}
*
* @param packageName package for which the extras are going to be applied;
*/
public ExtraProvider(String packageName) {
this.packageName = packageName;
this.overriddenText = null;
this.overriddenSubject = null;
this.overriddenImage = null;
this.textDisabled = false;
this.subjectDisabled = false;
this.imageDisabled = false;
}
/**
* Used to provide specific extras for a given package name.
* <p/>
* By default, every extras are going to be copied from the {@link IntentShare}.
* <p/>
* To override extras :
* {@link ExtraProvider#overrideText(String)}
* {@link ExtraProvider#overrideSubject(String)}
* {@link ExtraProvider#overrideImage(Uri)}
*
* @param in parcel.
*/
protected ExtraProvider(Parcel in) {
this.packageName = in.readString();
this.overriddenText = in.readString();
this.overriddenSubject = in.readString();
this.overriddenImage = in.readParcelable(Uri.class.getClassLoader());
this.textDisabled = in.readByte() != 0;
this.subjectDisabled = in.readByte() != 0;
this.imageDisabled = in.readByte() != 0;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExtraProvider that = (ExtraProvider) o;
if (textDisabled != that.textDisabled) {
return false;
}
if (subjectDisabled != that.subjectDisabled) {
return false;
}
if (imageDisabled != that.imageDisabled) {
return false;
}
if (packageName != null ? !packageName.equals(that.packageName)
: that.packageName != null) {
return false;
}
if (overriddenText != null ? !overriddenText.equals(that.overriddenText)
: that.overriddenText != null) {
return false;
}
if (overriddenSubject != null ? !overriddenSubject.equals(that.overriddenSubject)
: that.overriddenSubject != null) {
return false;
}
return !(overriddenImage != null ? !overriddenImage.equals(that.overriddenImage)
: that.overriddenImage != null);
}
@Override
public int hashCode() {
int result = packageName != null ? packageName.hashCode() : 0;
result = 31 * result + (overriddenText != null ? overriddenText.hashCode() : 0);
result = 31 * result + (overriddenSubject != null ? overriddenSubject.hashCode() : 0);
result = 31 * result + (overriddenImage != null ? overriddenImage.hashCode() : 0);
result = 31 * result + (textDisabled ? 1 : 0);
result = 31 * result + (subjectDisabled ? 1 : 0);
result = 31 * result + (imageDisabled ? 1 : 0);
return result;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.packageName);
dest.writeString(this.overriddenText);
dest.writeString(this.overriddenSubject);
dest.writeParcelable(this.overriddenImage, flags);
dest.writeByte(textDisabled ? (byte) 1 : (byte) 0);
dest.writeByte(subjectDisabled ? (byte) 1 : (byte) 0);
dest.writeByte(imageDisabled ? (byte) 1 : (byte) 0);
}
/**
* Provide a specific text for the linked package name.
*
* @param text text which will be used as {@link android.content.Intent#EXTRA_TEXT}
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider overrideText(String text) {
this.overriddenText = text;
return this;
}
/**
* Provide a specific subject for the linked package name.
*
* @param subject subject which will be used as {@link android.content.Intent#EXTRA_SUBJECT}
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider overrideSubject(String subject) {
this.overriddenSubject = subject;
return this;
}
/**
* Provide a specific image for the linked package name.
*
* @param image image which will be used as {@link android.content.Intent#EXTRA_STREAM}
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider overrideImage(Uri image) {
this.overriddenImage = image;
return this;
}
/**
* Disable the extra {@link android.content.Intent#EXTRA_TEXT} for the linked package
* to avoid a copy from the default {@link IntentShare} text.
*
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider disableText() {
this.textDisabled = true;
return this;
}
/**
* Disable the extra {@link android.content.Intent#EXTRA_SUBJECT} for the linked package
* to avoid a copy from the default {@link IntentShare} subject.
*
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider disableSubject() {
this.subjectDisabled = true;
return this;
}
/**
* Disable the extra {@link android.content.Intent#EXTRA_STREAM} for the linked package
* to avoid a copy from the default {@link IntentShare} image.
*
* @return {@link ExtraProvider} for chaining.
*/
public ExtraProvider disableImage() {
this.imageDisabled = true;
return this;
}
/**
* Get package name of the target activity for which the extra provider has been build.
*
* @return package name of the target activity for which the extra provider has been build.
*/
public String getPackageName() {
return packageName;
}
/**
* Retrieve the specific text which is going to override the default one.
*
* @return the specific text which is going to override the default one.
*/
public String getOverriddenText() {
return overriddenText;
}
/**
* Retrieve the subject which is going to override the default one.
*
* @return the subject which is going to override the default one.
*/
public String getOverriddenSubject() {
return overriddenSubject;
}
/**
* Retrieve the {@link Uri} which is going to override the default one.
*
* @return the {@link Uri} which is going to override the default one.
*/
public Uri getOverriddenImage() {
return overriddenImage;
}
/**
* Used to know if the default text must be ignored.
*
* @return true if the default text must be ignored.
*/
public boolean isTextDisabled() {
return textDisabled;
}
/**
* Used to know if the default subject must be ignored.
*
* @return true if the default subject must be ignored.
*/
public boolean isSubjectDisabled() {
return subjectDisabled;
}
/**
* Used to know if the default image must be ignored.
*
* @return true if the default image must be ignored.
*/
public boolean isImageDisabled() {
return imageDisabled;
}
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/IntentShareListener.java
================================================
package fr.tvbarthel.intentshare;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
/**
* Simple listener used to catch which activity the user choose.
*/
public abstract class IntentShareListener {
/**
* Action used to inform that the user as complete the sharing.
*/
private static final String ACTION_ON_COMPLETED = "fr.tvbarthel.intentshare.oncompleted";
/**
* Action used to inform that the user as cancel the sharing.
*/
private static final String ACTION_ON_CANCELED = "fr.tvbarthel.intentshare.oncanceled";
/**
* Bundle key used to pass the package name.
*/
private static final String EXTRA_PACKAGE_NAME = "fr.tvbarthel.intentshare.package";
/**
* Internal receiver.
*/
private final InternalReceiver internalReceiver;
/**
* Simple listener used to catch which activity the user chosen.
*/
public IntentShareListener() {
internalReceiver = new InternalReceiver() {
@Override
public void onCanceled() {
super.onCanceled();
IntentShareListener.this.onCanceled();
}
@Override
public void onCompleted(String packageName) {
super.onCompleted(packageName);
IntentShareListener.this.onCompleted(packageName);
}
};
}
/**
* Called when the user chose an activity to complete the sharing.
*
* @param packageName package name of the selected activity.
*/
public abstract void onCompleted(String packageName);
/**
* Called when the user cancel the sharing without selecting any target activity.
*/
public abstract void onCanceled();
/**
* Notify all registered listener that sharing has been completed.
* <p/>
* private package.
*
* @param context context used to send the broadcast.
* @param packageName package name of the selected target activity.
*/
static void notifySharingCompleted(Context context, String packageName) {
Intent intent = new Intent(ACTION_ON_COMPLETED);
intent.putExtra(EXTRA_PACKAGE_NAME, packageName);
LocalBroadcastManager.getInstance(context.getApplicationContext()).sendBroadcast(intent);
}
/**
* Notify all registered listener that sharing has been canceled
* <p/>
* private package.
*
* @param context context used to send the broadcast.
*/
static void notifySharingCanceled(Context context) {
Intent intent = new Intent(ACTION_ON_CANCELED);
LocalBroadcastManager.getInstance(context.getApplicationContext()).sendBroadcast(intent);
}
/**
* Used to register the internal listener.
* <p/>
* private package.
*
* @param context context used to register the listener.
*/
void register(Context context) {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_ON_COMPLETED);
filter.addAction(ACTION_ON_CANCELED);
LocalBroadcastManager.getInstance(context.getApplicationContext())
.registerReceiver(internalReceiver, filter);
}
/**
* Receiver used internally to catch event.
*/
private static class InternalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case ACTION_ON_COMPLETED:
onCompleted(intent.getStringExtra(EXTRA_PACKAGE_NAME));
break;
case ACTION_ON_CANCELED:
onCanceled();
break;
default:
throw new IllegalArgumentException("Action unknown : " + intent.getAction());
}
// unregister receiver.
LocalBroadcastManager.getInstance(context.getApplicationContext()).unregisterReceiver(this);
}
/**
* Called when the user chose an activity to complete the sharing.
*
* @param packageName package name of the selected activity.
*/
public void onCompleted(String packageName) {
}
/**
* Called when the user cancel the sharing without selecting any target activity.
*/
public void onCanceled() {
}
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/LayoutManagerFactory.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.os.Build;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
/**
* Factory used to handle layout manager according to the device android version seamlessly
*/
final class LayoutManagerFactory {
private static final int MARSHMALLOW_SPAN_COUNT = 4;
/**
* Non instantiable class.
*/
private LayoutManagerFactory() {
}
/**
* Build the layout manager for the {@link TargetActivity} list displayed to the user
* during the target activity selection.
*
* @param context context used to instantiate layout manager.
* @return layout manager matching the native look and feel linked to the device SDK version.
*/
public static RecyclerView.LayoutManager buildLayoutManager(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
GridLayoutManager gridLayoutManager = new GridLayoutManager(context, MARSHMALLOW_SPAN_COUNT);
gridLayoutManager.setSpanSizeLookup(new MarshmallowSpanSizeLookup());
return gridLayoutManager;
} else {
return new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
}
}
/**
* SpanSizeLookup used to fit the native look and feel provided by
* {@link android.content.Intent#createChooser(android.content.Intent, CharSequence)}
*/
private static final class MarshmallowSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
@Override
public int getSpanSize(int position) {
if (position == 0) {
return MARSHMALLOW_SPAN_COUNT; // header taking the full width;
} else {
return 1; // target activity taking one unit;
}
}
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/StyledAttributesUtils.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.TypedValue;
/**
* Util used to retrieved attributes of the current style.
*/
final class StyledAttributesUtils {
/**
* non instantiable class.
*/
private StyledAttributesUtils() {
}
/**
* Retrieve the selectable background of the current style.
*
* @param context context used to retrieve the styled attributes.
* @return selectable item background res id.
*/
public static int getSelectableItemBackground(Context context) {
int selectableItemBackgroundResId;
int[] attrs = new int[]{android.R.attr.selectableItemBackground};
TypedValue values = new TypedValue();
TypedArray array = context.obtainStyledAttributes(values.data, attrs);
selectableItemBackgroundResId = array.getResourceId(0, 0);
array.recycle();
return selectableItemBackgroundResId;
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivity.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Parcel;
import java.io.File;
import java.util.Comparator;
/**
* Plain java model for a sharing target activity.
*/
public class TargetActivity {
private final int activityLabelResId;
private final Uri iconUri;
private final boolean isMail;
private final long lastSelection;
private ResolveInfo resolveInfo;
private CharSequence label;
/**
* Plain java model for a sharing target activity.
*
* @param context context used to load target activity label.
* @param resolveInfo {@link ResolveInfo} linked to the target activity.
* @param lastSelection time stamp in milli of last selection.
*/
public TargetActivity(Context context, ResolveInfo resolveInfo, long lastSelection) {
this.lastSelection = lastSelection;
this.resolveInfo = resolveInfo;
int icon = resolveInfo.activityInfo.icon;
if (icon == 0) {
icon = resolveInfo.activityInfo.applicationInfo.icon;
}
this.iconUri = Uri.parse(
"android.resource://"
+ resolveInfo.activityInfo.applicationInfo.packageName
+ File.separator
+ icon
);
this.activityLabelResId = resolveInfo.labelRes;
this.isMail = resolveInfo.filter.hasDataType("message/rfc822");
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TargetActivity that = (TargetActivity) o;
return resolveInfo.equals(that.resolveInfo);
}
@Override
public int hashCode() {
int result = activityLabelResId;
result = 31 * result + resolveInfo.hashCode();
return result;
}
/**
* Retrieve a unique id used to identify target activity.
*
* @return unique id used to identify target activity.
*/
public String getId() {
return this.resolveInfo.activityInfo.packageName
+ this.resolveInfo.activityInfo.name;
}
/**
* Retrieve the package name of the target activity.
*
* @return package name.
*/
public String getPackageName() {
return resolveInfo.activityInfo.packageName;
}
/**
* Retrive the name of the target activity.
*
* @return activity name.
*/
public String getActivityName() {
return resolveInfo.activityInfo.name;
}
/**
* Retrieve the textual label res id of the Activity.
*
* @return textual label res id of the Activity.
*/
public int getActivityLabelResId() {
return activityLabelResId;
}
/**
* Retrieve the Uri used to access to the target application launcher icon.
*
* @return uri linking to the application launcher icon.
*/
public Uri getIconUri() {
return iconUri;
}
/**
* Used to know if the target activity is a mail client.
* <p/>
* Basically, any activity which can handle type 'message/rfc_822'.
*
* @return true if the target activity is a mail client, false otherwise.
*/
public boolean isMailClient() {
return this.isMail;
}
/**
* Return a timestamp of the last selection inside the sharing dialog from you application.
*
* @return timestamp of the last selection in milliseconds since January 1, 1970 00:00:00.0 UTC
* or 0 if the target activity has never been selected by the user.
*/
public long getLastSelection() {
return lastSelection;
}
/**
* Retrieve the label of the target activity.
*
* @return return target activity label or null if not yet loaded.
*/
CharSequence getLabel() {
return label;
}
/**
* Resolve info linked to the target activity.
*
* @return Resolve info linked to the target activity.
*/
ResolveInfo getResolveInfo() {
return resolveInfo;
}
/**
* Label of the target activity.
*
* @param label label of the target activity.
*/
void setLabel(CharSequence label) {
this.label = label;
}
/**
* Comparator used to sort {@link TargetActivity} based on the recency of their previous
* selection and their default order as fallback when they have never been selected.
* <p/>
* The ordering imposed by this comparator on a set of {@link TargetActivity}
* is not consistent with equals since c.compare(e1, e2)==0 has not the same boolean
* value as e1.equals(e2).
*/
public static final class RecencyComparatorProvider implements TargetActivityComparatorProvider {
/**
* Parcelable.
*/
public static final Creator<RecencyComparatorProvider> CREATOR = new Creator<RecencyComparatorProvider>() {
@Override
public RecencyComparatorProvider createFromParcel(Parcel source) {
return new RecencyComparatorProvider(source);
}
@Override
public RecencyComparatorProvider[] newArray(int size) {
return new RecencyComparatorProvider[size];
}
};
/**
* Comparator used to sort {@link TargetActivity} based on the recency of their previous
* selection and their default order as fallback when they have never been selected.
* <p/>
* The ordering imposed by this comparator on a set of {@link TargetActivity}
* is not consistent with equals since c.compare(e1, e2)==0 has not the same boolean
* value as e1.equals(e2).
*/
public RecencyComparatorProvider() {
}
/**
* Comparator used to sort {@link TargetActivity} based on the recency of their previous
* selection and their default order as fallback when they have never been selected.
* <p/>
* The ordering imposed by this comparator on a set of {@link TargetActivity}
* is not consistent with equals since c.compare(e1, e2)==0 has not the same boolean
* value as e1.equals(e2).
*
* @param in parcel.
*/
protected RecencyComparatorProvider(Parcel in) {
}
@Override
public Comparator<TargetActivity> provideComparator() {
return new Comparator<TargetActivity>() {
@Override
public int compare(TargetActivity lhs, TargetActivity rhs) {
float lhsScore = lhs.lastSelection;
float rhsScore = rhs.lastSelection;
if (lhsScore > 0 && rhsScore > 0) {
return (int) (rhsScore - lhsScore);
} else if (lhsScore > 0) {
return -1;
} else if (rhsScore > 0) {
return 1;
} else {
return 0;
}
}
};
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityAdapter.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import java.util.List;
/**
* Used to adapt {@link TargetActivityView} inside a list.
*/
class TargetActivityAdapter extends RecyclerView.Adapter<TargetActivityAdapter.ViewHolder> {
/**
* View types.
*/
private static final int VIEW_TYPE_HEADER = 0x00000001;
private static final int VIEW_TYPE_RAW = 0x00000002;
private final String label;
private final IconLoader iconLoader;
/**
* Target activity info adapted.
*/
private List<TargetActivity> targetActivities;
/**
* Internal listener used to catch the events from the {@link TargetActivityView} adapted.
*/
private TargetActivityView.Listener internalTargetActivityViewListener;
/**
* Listener used to catch adapted views events.
*/
private Listener listener;
/**
* Used to adapt {@link TargetActivityView} inside a list.
*
* @param targetActivities list of target activities.
* @param label label to display as an header of the list.
* @param iconLoader loader used to load {@link TargetActivity} icon.
*/
public TargetActivityAdapter(final List<TargetActivity> targetActivities,
String label,
IconLoader iconLoader) {
this.targetActivities = targetActivities;
this.label = label;
internalTargetActivityViewListener = new TargetActivityView.Listener() {
@Override
public void onTargetActivitySelected(TargetActivity targetActivity) {
if (listener != null) {
listener.onTargetActivitySelected(targetActivity);
}
}
};
this.iconLoader = iconLoader;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
Context context = parent.getContext();
switch (viewType) {
case VIEW_TYPE_HEADER:
TargetActivityHeaderView headerView
= new TargetActivityHeaderView(context);
headerView.setLayoutParams(layoutParams);
int extraPadding = context.getResources()
.getDimensionPixelSize(R.dimen.isl_target_activity_header_extra_padding);
headerView.setPadding(
headerView.getPaddingLeft() + extraPadding,
headerView.getPaddingTop(),
headerView.getRight() + extraPadding,
headerView.getPaddingBottom()
);
return new ViewHolder(headerView);
case VIEW_TYPE_RAW:
TargetActivityView targetActivityView
= new TargetActivityView(context, iconLoader);
targetActivityView.setLayoutParams(layoutParams);
targetActivityView.setListener(internalTargetActivityViewListener);
return new ViewHolder(targetActivityView);
default:
throw new IllegalStateException("Can't create view "
+ "holder for the given view type : " + viewType);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case VIEW_TYPE_HEADER:
((TargetActivityHeaderView) holder.itemView).setModel(label);
break;
case VIEW_TYPE_RAW:
// -1 for the header.
TargetActivityView targetActivityView = (TargetActivityView) holder.itemView;
targetActivityView.setModel(targetActivities.get(position - 1));
targetActivityView.loadIcon();
break;
default:
throw new IllegalStateException("Can't bind view "
+ "holder for view type : " + holder.getItemViewType());
}
}
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
if (holder.itemView instanceof TargetActivityView) {
((TargetActivityView) holder.itemView).cancelIconLoading();
}
}
@Override
public int getItemCount() {
// +1 for the header
return targetActivities.size() + 1;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return VIEW_TYPE_HEADER;
} else {
return VIEW_TYPE_RAW;
}
}
/**
* Listener used to catch events from the adapted views.
*
* @param listener listener to register.
*/
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Used to notify that a target activity changed.
*
* @param targetActivity target activity which have changed.
*/
public void notifyTargetActivityChanged(TargetActivity targetActivity) {
int in = targetActivities.indexOf(targetActivity);
if (in != -1) {
notifyItemChanged(in + 1); // header
}
}
/**
* View holder pattern.
*/
public class ViewHolder extends RecyclerView.ViewHolder {
/**
* View holder.
*
* @param itemView {@link TargetActivityView}
*/
public ViewHolder(TargetActivityView itemView) {
super(itemView);
}
/**
* View holder.
*
* @param headerView {@link TargetActivityHeaderView}
*/
public ViewHolder(TargetActivityHeaderView headerView) {
super(headerView);
}
}
/**
* Listener used to catch events from adapted views.
*/
public interface Listener {
/**
* Called when the user has chosen a target activity for the initial share intent.
*
* @param targetActivity chosen target activity.
*/
void onTargetActivitySelected(TargetActivity targetActivity);
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityComparatorProvider.java
================================================
package fr.tvbarthel.intentshare;
import android.os.Parcelable;
import java.util.Comparator;
/**
* ˙Interface which allow to define which comparator will be provided for sorting the
* target activity inside the {@link TargetChooserActivity}.
*/
public interface TargetActivityComparatorProvider extends Parcelable {
/**
* Provide the comparator used to sort {@link TargetActivity} displayed to the user.
*
* @return comparator used to sort {@link TargetActivity} displayed to the user.
*/
Comparator<TargetActivity> provideComparator();
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityHeaderView.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
/**
* Simple view used to display the label above the target activity list.
*/
class TargetActivityHeaderView extends TextView {
/**
* view height
*/
private int height;
/**
* Simple view used to display the label above the target activity list.
*
* @param context holding context.
*/
public TargetActivityHeaderView(Context context) {
this(context, null);
}
/**
* Simple view used to display the label above the target activity list.
*
* @param context holding context.
* @param attrs attr from xml.
*/
public TargetActivityHeaderView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* Simple view used to display the label above the target activity list.
*
* @param context holding context.
* @param attrs attr from xml.
* @param defStyleAttr style.
*/
public TargetActivityHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (!isInEditMode()) {
initialize(context);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
/**
* Set the label which going to be displayed inside the header.
*
* @param label label to display inside the header.
*/
public void setModel(String label) {
setText(label);
}
/**
* Initialize internal component
*
* @param context holding context.
*/
private void initialize(Context context) {
setBackgroundColor(
ContextCompat.getColor(
context,
R.color.isl_target_activity_header_view_background
)
);
Resources resources = context.getResources();
height = resources.getDimensionPixelSize(R.dimen.isl_target_activity_header_view_height);
setTextSize(
TypedValue.COMPLEX_UNIT_PX,
resources.getDimensionPixelSize(R.dimen.isl_target_activity_header_view_font_size)
);
setTextColor(
ContextCompat.getColor(
context,
R.color.isl_target_activity_header_view_text_color
)
);
setSingleLine(true);
setEllipsize(TextUtils.TruncateAt.END);
int padding = resources.getDimensionPixelSize(R.dimen.isl_default_padding);
setPadding(getPaddingLeft(), padding, getPaddingRight(), padding);
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityManager.java
================================================
package fr.tvbarthel.intentshare;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Manager used to handle all logic linked to {@link TargetActivity}
*/
class TargetActivityManager {
/**
* Shared preferences key used to store chosen activities.
*/
private static final String SHARED_PREF_KEY = "shared_pref_target_activities";
/**
* Pattern for last selection key.
* string 1 : package name
* string 2 : activity name
*/
private static final String KEY_LAST_SELECTION = "shared_pref_last_selection_$1%s_$2%s";
/**
* List of target activities.
*/
private ArrayList<TargetActivity> targetActivities;
/**
* Shared preferences used to store target activities scores.
*/
private SharedPreferences sharedPreferences;
/**
* Manager used to handle all logic linked to {@link TargetActivity}
*/
public TargetActivityManager() {
targetActivities = new ArrayList<>();
}
/**
* Resolve the list of {@link android.app.Activity} which can be targeted for sharing content.
* <p/>
* Basically, resolve the list of {@link android.app.Activity} which can handled
* {@link Intent#ACTION_SEND}.
*
* @param context context used to resolves target activities.
* @param listener listener used to catch resolving events.
* @param comparator comparator used to sort the resolved target activities.
*/
public void resolveTargetActivities(Context context, ResolveListener listener,
Comparator<TargetActivity> comparator) {
targetActivities.clear();
sharedPreferences = context.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE);
PackageManager packageManager = context.getPackageManager();
Intent intentShare = new Intent(Intent.ACTION_SEND);
intentShare.putExtra(Intent.EXTRA_TEXT, "queryText");
intentShare.setType("text/plain");
List<ResolveInfo> shareActivities = packageManager.queryIntentActivities(
intentShare,
PackageManager.GET_RESOLVED_FILTER
);
for (int i = 0; i < shareActivities.size(); i++) {
ResolveInfo targetActivityInfo = shareActivities.get(i);
IntentFilter filter = targetActivityInfo.filter;
if (filter.hasDataType("text/plain")) {
String lastSelectionKey = getLastSelectionKey(
targetActivityInfo.activityInfo.packageName,
targetActivityInfo.activityInfo.name
);
long lastSelection = sharedPreferences.getLong(lastSelectionKey, 0);
TargetActivity targetActivity
= new TargetActivity(context, targetActivityInfo, lastSelection);
targetActivities.add(targetActivity);
}
}
Collections.sort(targetActivities, comparator);
for (int i = 0; i < targetActivities.size(); i++) {
new AsyncLabelLoader(context, targetActivities.get(i), listener).execute();
}
listener.onTargetActivitiesResolved(targetActivities);
}
private String getLastSelectionKey(String packageName, String activityName) {
return String.format(KEY_LAST_SELECTION, packageName, activityName);
}
/**
* Start a target activity with well field params according to the given {@link IntentShare}
*
* @param context context used to start the activity.
* @param targetActivity target activity to start.
* @param intentShare data which should be send to the target activity.
*/
public void startTargetActivity(Context context, TargetActivity targetActivity, IntentShare intentShare) {
context.startActivity(
buildTargetActivityIntent(
targetActivity,
intentShare
)
);
sharedPreferences
.edit()
.putLong(getLastSelectionKey(
targetActivity.getPackageName(),
targetActivity.getActivityName()
),
System.currentTimeMillis()
)
.apply();
}
/**
* Build the intent with {@link Intent#ACTION_SEND} action used to start the target activity
* with well field params according to the given {@link IntentShare}.
*
* @param targetActivity target activity which should be start.
* @param intentShare shared content used to field the intent params.
* @return {@link Intent#ACTION_SEND} field to start the target activity.
*/
private Intent buildTargetActivityIntent(TargetActivity targetActivity, IntentShare intentShare) {
String packageName = targetActivity.getPackageName();
String activityName = targetActivity.getActivityName();
ComponentName componentName = new ComponentName(
packageName,
activityName
);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
if (targetActivity.isMailClient()) { // mail target
intent.putExtra(Intent.EXTRA_TEXT, intentShare.mailBody);
intent.putExtra(Intent.EXTRA_SUBJECT, intentShare.mailSubject);
addImageExtras(intent, intentShare.imageUri);
} else { // other target
intent.putExtra(Intent.EXTRA_TEXT, intentShare.text);
addImageExtras(intent, intentShare.imageUri);
}
applyExtraProvider(intent, packageName, intentShare.extraProviders);
intent.setComponent(componentName);
return intent;
}
/**
* Apply the extra provider to the current intent if one is associated to the targeted package.
*
* @param intent intent send.
* @param targetPackageName targeted package.
* @param extraProviders list of extra providers.
*/
private void applyExtraProvider(
Intent intent,
String targetPackageName,
ArrayList<IntentShare.ExtraProvider> extraProviders) {
IntentShare.ExtraProvider extraProvider = null;
for (int i = 0; i < extraProviders.size(); i++) {
IntentShare.ExtraProvider provider = extraProviders.get(i);
if (provider.packageName.equals(targetPackageName)) {
extraProvider = provider;
break;
}
}
if (extraProvider != null) {
if (extraProvider.textDisabled) {
intent.removeExtra(Intent.EXTRA_TEXT);
} else if (extraProvider.overriddenText != null) {
intent.putExtra(Intent.EXTRA_TEXT, extraProvider.overriddenText);
}
if (extraProvider.subjectDisabled) {
intent.removeExtra(Intent.EXTRA_SUBJECT);
} else if (extraProvider.overriddenSubject != null) {
intent.putExtra(Intent.EXTRA_SUBJECT, extraProvider.overriddenSubject);
}
if (extraProvider.imageDisabled) {
intent.removeExtra(Intent.EXTRA_STREAM);
intent.setType("text/plain");
} else if (extraProvider.overriddenImage != null) {
intent.putExtra(Intent.EXTRA_STREAM, extraProvider.overriddenImage);
}
}
}
private void addImageExtras(Intent intent, Uri imageUri) {
if (imageUri != null) {
intent.putExtra(Intent.EXTRA_STREAM, imageUri);
intent.setType("image/jpeg");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
/**
* Listener used to catch resolve events.
*/
public interface ResolveListener {
/**
* Called when the target activities has been resolved.
* <p/>
* Note that, since resolving target activities name can take a little more time,
* {@link ResolveListener#onLabelResolved(TargetActivity)}
* will be called once a label has been successfully loaded.
*
* @param targetActivities list of resolved target activities.
*/
void onTargetActivitiesResolved(@NonNull ArrayList<TargetActivity> targetActivities);
/**
* Called when the label of a target activity has been resolved.
*
* @param targetActivity target for which the label has been resolved.
*/
void onLabelResolved(@NonNull TargetActivity targetActivity);
}
/**
* Async task used to avoid loading the target activity label on the ui thread.
*/
private static final class AsyncLabelLoader extends AsyncTask<Void, Void, CharSequence> {
private final PackageManager packageManager;
private final TargetActivity targetActivity;
private final ResolveListener listener;
/**
* Async task used to avoid loading the target activity label on the ui thread.
*
* @param context context used to access to the package manager.
* @param targetActivity target activity for which the label should be loaded.
* @param listener to notify once the label has been loaded.
*/
public AsyncLabelLoader(
@NonNull Context context,
@NonNull TargetActivity targetActivity,
@NonNull ResolveListener listener) {
packageManager = context.getPackageManager();
this.targetActivity = targetActivity;
this.listener = listener;
}
@Override
protected CharSequence doInBackground(Void... params) {
return targetActivity.getResolveInfo().loadLabel(packageManager);
}
@Override
protected void onPostExecute(CharSequence s) {
super.onPostExecute(s);
targetActivity.setLabel(s);
listener.onLabelResolved(targetActivity);
}
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityView.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Simple view used to display a {@link TargetActivity}.
*/
class TargetActivityView extends FrameLayout {
private ImageView icon;
private TextView label;
private TargetActivity model;
private OnClickListener mInternalClickListener;
private Listener listener;
private int height;
private IconLoader asyncIconLoader;
/**
* Simple view used to display a {@link TargetActivity}.
*
* @param context holding context.
* @param asyncIconLoader loader used to load {@link TargetActivity} icon.
*/
public TargetActivityView(Context context, IconLoader asyncIconLoader) {
super(context);
if (!isInEditMode()) {
initialize(context);
}
this.asyncIconLoader = asyncIconLoader;
}
/**
* Simple view used to display a {@link TargetActivity}.
*
* @param context holding context.
* @param attrs attr from xml.
*/
public TargetActivityView(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
initialize(context);
}
}
/**
* Simple view used to display a {@link TargetActivity}.
*
* @param context holding context.
* @param attrs attr from xml.
* @param defStyleAttr style.
*/
public TargetActivityView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (!isInEditMode()) {
initialize(context);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
/**
* Set the view model.
*
* @param model view model.
*/
public void setModel(TargetActivity model) {
this.model = model;
label.setText(model.getLabel());
}
/**
* Set a listener used to catch view events.
*
* @param listener listener to register.
*/
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Load the target activity icon.
*/
public void loadIcon() {
icon.setImageDrawable(null);
asyncIconLoader.load(model.getIconUri(), icon);
}
/**
* Cancel the loading of the target activity icon.
*/
public void cancelIconLoading() {
asyncIconLoader.cancel(icon);
}
/**
* Initialize internal component.
*
* @param context holding context.
*/
private void initialize(Context context) {
LayoutInflater.from(context).inflate(R.layout.isl_target_activity_view, this);
Resources resources = context.getResources();
height = resources.getDimensionPixelSize(R.dimen.isl_target_activity_view_height);
int paddingVertical = resources.getDimensionPixelSize(R.dimen.isl_target_activity_padding_vertical);
int paddingHorizontal = resources.getDimensionPixelSize(R.dimen.isl_target_activity_padding_horizontal);
setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical);
setForeground(
ContextCompat.getDrawable(
context,
StyledAttributesUtils.getSelectableItemBackground(context)
)
);
icon = ((ImageView) findViewById(R.id.target_activity_view_icon));
label = ((TextView) findViewById(R.id.target_activity_view_label));
mInternalClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onTargetActivitySelected(model);
}
}
};
setOnClickListener(mInternalClickListener);
}
/**
* Listener used to catch view events.
*/
public interface Listener {
/**
* Called when the user has chosen a target activity for his share intent.
*
* @param targetActivity chosen target activity.
*/
void onTargetActivitySelected(TargetActivity targetActivity);
}
}
================================================
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetChooserActivity.java
================================================
package fr.tvbarthel.intentshare;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Simple activity used to allow the user to choose a target activity for the sharing intent.
*/
public class TargetChooserActivity extends AppCompatActivity
implements TargetActivityAdapter.Listener, View.OnClickListener, TargetActivityManager.ResolveListener {
/**
* Extra key used to pass param to the activity.
*/
private static final String EXTRA_INTENT_SHARE = "tca_extra_intent_share";
/**
* Key used to save the current scroll during rotation.
*/
private static final String SAVED_CURRENT_SCROLL_Y = "tca_saved_instance_key_current_scroll";
/**
* Recycler view used to display the list of target application.
*/
private RecyclerView recyclerView;
/**
* Padding top applied to the recycler view.
*/
private int recyclerPaddingTop;
/**
* Adapter used to display target activity inside a list.
*/
private TargetActivityAdapter adapter;
/**
* Values to share retrieved from intent extras.
*/
private TargetActivityManager targetActivityManager;
/**
* Date which must be shared.
*/
private IntentShare intentShare;
/**
* Height in of a {@link TargetActivityView}
*/
private int targetActivityViewHeight;
/**
* Target activity selected by the user.
*/
private TargetActivity selectedTargetActivity;
/**
* Used to know if listener has been notified.
*/
private boolean listenerNotified;
/**
* Sticky header view displayed to keep an eye on the contextual action when the
* header inside the list is hidden.
*/
private TargetActivityHeaderView stickyTitle;
/**
* Sticky header shadow.
*/
private View stickyShadow;
/**
* Boolean used to know if the sticky header is displayed.
*/
private boolean isStickyTitleDisplayed;
/**
* Used to keep current recycler scroll y up to date.
*/
private int currentRecyclerScrollY;
/**
* Root view of the activity
*/
private View rootView;
/**
* List of sharing target activity.
*/
private List<TargetActivity> targetActivities;
/**
* Duration in milli.
*/
private long animationDuration;
/**
* Interpolator for element which enter the screen.
*/
private Interpolator inInterpolator;
/**
* Interpolator for element which leave the screen.
*/
private Interpolator outInterpolator;
/**
* View used as background since recycler view padding can't allow to used
* recycler background directly.
*/
private View background;
/**
* Used to know if the activity state has been restored after a saved instance.
*/
private boolean stateRestored;
/**
* Simple activity used to allow the user to choose a target activity for the sharing intent.
*
* @param context context used to start the activity.
* @param intentShare data to share
*/
public static void start(Context context, IntentShare intentShare) {
Intent intent = new Intent(context, TargetChooserActivity.class);
intent.putExtra(EXTRA_INTENT_SHARE, intentShare);
context.startActivity(intent);
if (context instanceof Activity) {
((Activity) context).overridePendingTransition(-1, -1);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras == null || !extras.containsKey(EXTRA_INTENT_SHARE)) {
throw new IllegalArgumentException("Fail to start activity due to missing mandatory extras."
+ "Use start activity pattern.");
}
intentShare = extras.getParcelable(EXTRA_INTENT_SHARE);
setContentView(R.layout.isl_activity_target_chooser);
rootView = findViewById(R.id.activity_target_chooser_root_view);
recyclerView = ((RecyclerView) findViewById(R.id.activity_target_chooser_recycler_list));
stickyTitle = ((TargetActivityHeaderView) findViewById(R.id.activity_chooser_sticky_title));
stickyShadow = findViewById(R.id.activity_chooser_sticky_title_shadow);
background = findViewById(R.id.activity_target_chooser_background);
targetActivities = new ArrayList<>();
selectedTargetActivity = null;
listenerNotified = false;
Resources resources = getResources();
animationDuration = resources.getInteger(android.R.integer.config_mediumAnimTime);
rootView.setOnClickListener(this);
rootView.setAlpha(0f);
stateRestored = savedInstanceState != null;
setUpRecyclerView(savedInstanceState);
setUpStickyTitle();
targetActivityManager = new TargetActivityManager();
targetActivityManager.resolveTargetActivities(this, this, intentShare.comparatorProvider.provideComparator());
inInterpolator = new DecelerateInterpolator();
outInterpolator = new AccelerateInterpolator();
}
@Override
public void onBackPressed() {
finishAnimated();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SAVED_CURRENT_SCROLL_Y, currentRecyclerScrollY);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!listenerNotified && !isChangingConfigurations()) {
IntentShareListener.notifySharingCanceled(this);
}
}
@Override
public void finish() {
super.finish();
if (selectedTargetActivity != null) {
IntentShareListener.notifySharingCompleted(this, selectedTargetActivity.getPackageName());
} else if (!isChangingConfigurations()) {
IntentShareListener.notifySharingCanceled(this);
}
listenerNotified = true;
}
@Override
public void onClick(View v) {
finishAnimated();
}
@Override
public void onTargetActivitiesResolved(@NonNull ArrayList<TargetActivity> targetActivities) {
this.targetActivities.addAll(targetActivities);
adapter.notifyDataSetChanged();
}
@Override
public void onTargetActivitySelected(@NonNull TargetActivity targetActivity) {
selectedTargetActivity = targetActivity;
targetActivityManager.startTargetActivity(this, targetActivity, intentShare);
finish();
}
@Override
public void onLabelResolved(TargetActivity targetActivity) {
adapter.notifyTargetActivityChanged(targetActivity);
}
private void setUpRecyclerView(Bundle savedInstance) {
recyclerView.setLayoutManager(LayoutManagerFactory.buildLayoutManager(this));
targetActivities = new ArrayList<>();
adapter = new TargetActivityAdapter(
targetActivities,
intentShare.chooserTitle,
intentShare.iconLoader
);
adapter.setListener(this);
targetActivityViewHeight = getResources().getDimensionPixelSize(R.dimen.isl_target_activity_view_height);
if (savedInstance != null) {
currentRecyclerScrollY = savedInstance.getInt(SAVED_CURRENT_SCROLL_Y, 0);
} else {
currentRecyclerScrollY = 0;
}
recyclerView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
int totalHeight = adapter.getItemCount() * targetActivityViewHeight;
int maxStartingHeight = (int) (recyclerView.getHeight() / 2.5f);
int startingHeight = Math.min(totalHeight, maxStartingHeight);
recyclerPaddingTop = recyclerView.getHeight() - startingHeight;
recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerPaddingTop,
recyclerView.getPaddingRight(), 0);
recyclerView.setTranslationY(recyclerView.getHeight());
int backgroundTranslationY = Math.max(0, recyclerPaddingTop - currentRecyclerScrollY);
background.setTranslationY(recyclerView.getHeight() + backgroundTranslationY);
recyclerView.setAdapter(adapter);
if (stateRestored) {
rootView.setAlpha(1f);
recyclerView.setTranslationY(0);
background.setTranslationY(backgroundTranslationY);
} else {
rootView.animate()
.alpha(1f)
.setDuration(animationDuration)
.setInterpolator(inInterpolator)
.setListener(null);
recyclerView.animate()
.translationY(0)
.setDuration(animationDuration)
.setInterpolator(inInterpolator)
.setListener(null);
background.animate()
.translationY(backgroundTranslationY)
.setDuration(animationDuration)
.setInterpolator(inInterpolator)
.setListener(null);
}
return false;
}
}
);
recyclerView.addOnScrollListener(
new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
currentRecyclerScrollY += dy;
if (!isStickyTitleDisplayed && currentRecyclerScrollY >= recyclerPaddingTop) {
isStickyTitleDisplayed = true;
stickyTitle.setVisibility(View.VISIBLE);
stickyShadow.setVisibility(View.VISIBLE);
} else if (currentRecyclerScrollY < recyclerPaddingTop) {
if (isStickyTitleDisplayed) {
isStickyTitleDisplayed = false;
stickyTitle.setVisibility(View.INVISIBLE);
stickyShadow.setVisibility(View.INVISIBLE);
}
background.setTranslationY(recyclerPaddingTop - currentRecyclerScrollY);
}
}
}
);
}
private void setUpStickyTitle() {
stickyTitle.setVisibility(View.INVISIBLE);
stickyShadow.setVisibility(View.INVISIBLE);
stickyTitle.setModel(intentShare.chooserTitle);
isStickyTitleDisplayed = false;
}
private void finishAnimated() {
rootView.animate()
.alpha(0)
.setDuration(animationDuration)
.setInterpolator(outInterpolator)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
TargetChooserActivity.this.finish();
TargetChooserActivity.this.overridePendingTransition(-1, -1);
}
}
);
recyclerView.animate()
.translationY(rootView.getHeight())
.setDuration(animationDuration)
.setInterpolator(outInterpolator)
.setListener(null);
background.animate()
.translationY(background.getTranslationY() + rootView.getHeight())
.setDuration(animationDuration)
.setInterpolator(outInterpolator)
.setListener(null);
stickyShadow.animate()
.translationY(rootView.getHeight())
.setDuration(animationDuration)
.setInterpolator(outInterpolator)
.setListener(null);
stickyTitle.animate()
.translationY(rootView.getHeight())
.setDuration(animationDuration)
.setInterpolator(outInterpolator)
.setListener(null);
}
}
================================================
FILE: library/src/main/res/layout/isl_activity_target_chooser.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_target_chooser_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/isl_activity_translucent_background"
android:fitsSystemWindows="true">
<View
android:id="@+id/activity_target_chooser_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/isl_target_activity_view_background" />
<fr.tvbarthel.intentshare.BottomRecyclerView
android:id="@+id/activity_target_chooser_recycler_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:overScrollMode="never"
android:paddingLeft="@dimen/isl_target_activity_recycler_padding"
android:paddingRight="@dimen/isl_target_activity_recycler_padding" />
<fr.tvbarthel.intentshare.TargetActivityHeaderView
android:id="@+id/activity_chooser_sticky_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/isl_default_padding"
android:paddingRight="@dimen/isl_default_padding" />
<View
android:id="@+id/activity_chooser_sticky_title_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_marginTop="@dimen/isl_target_activity_header_view_height"
android:background="@drawable/isl_shadow_bottom" />
</FrameLayout>
================================================
FILE: library/src/main/res/layout/isl_target_activity_view.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/target_activity_view_icon"
android:layout_width="@dimen/isl_target_activity_view_icon_size"
android:layout_height="@dimen/isl_target_activity_view_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/isl_target_activity_icon_margin_left"/>
<TextView
android:id="@+id/target_activity_view_label"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/isl_target_activity_view_label_icon_margin"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/isl_target_activity_view_label"
android:textSize="@dimen/isl_target_activity_view_text_size"/>
</merge>
================================================
FILE: library/src/main/res/layout-v23/isl_target_activity_view.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/target_activity_view_icon"
android:layout_width="@dimen/isl_target_activity_view_icon_size"
android:layout_height="@dimen/isl_target_activity_view_icon_size"
android:layout_gravity="center_horizontal|top"
android:layout_marginLeft="@dimen/isl_target_activity_icon_margin_left" />
<TextView
android:id="@+id/target_activity_view_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/isl_target_activity_view_label_icon_margin"
android:ellipsize="end"
android:fontFamily="sans-serif-condensed"
android:gravity="center"
android:maxLines="2"
android:textColor="@color/isl_target_activity_view_label"
android:textSize="@dimen/isl_target_activity_view_text_size" />
</merge>
================================================
FILE: library/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="isl_target_activity_view_label">#212121</color>
<color name="isl_target_activity_view_background">@android:color/white</color>
<color name="isl_target_activity_header_view_background">@android:color/white</color>
<color name="isl_target_activity_header_view_text_color">#767676</color>
<color name="isl_activity_translucent_background">#88000000</color>
</resources>
================================================
FILE: library/src/main/res/values/dimens.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="isl_default_padding">16dp</dimen>
<!-- Target Activity View !-->
<dimen name="isl_target_activity_padding_vertical">16dp</dimen>
<dimen name="isl_target_activity_padding_horizontal">16dp</dimen>
<dimen name="isl_target_activity_view_icon_size">24dp</dimen>
<dimen name="isl_target_activity_icon_margin_left">10dp</dimen>
<dimen name="isl_target_activity_view_label_icon_margin">54dp</dimen>
<dimen name="isl_target_activity_header_view_font_size">19sp</dimen>
<dimen name="isl_target_activity_header_view_height">60dp</dimen>
<dimen name="isl_target_activity_view_height">60dp</dimen>
<dimen name="isl_target_activity_view_text_size">19sp</dimen>
<dimen name="isl_target_activity_recycler_padding">0dp</dimen>
<dimen name="isl_target_activity_header_extra_padding">@dimen/isl_default_padding</dimen>
</resources>
================================================
FILE: library/src/main/res/values/public.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<public name="IntentShareTheme" type="style" tools:ignore="ResourceName" />
</resources>
================================================
FILE: library/src/main/res/values/strings.xml
================================================
<resources>
<string name="isl_default_sharing_label">Share with</string>
</resources>
================================================
FILE: library/src/main/res/values/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="IntentShareTheme" parent="isl_ActivityThemeBase" tools:ignore="ResourceName">
<!-- Customize your theme here. -->
</style>
<style name="isl_ActivityThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>
================================================
FILE: library/src/main/res/values-v19/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="IntentShareTheme" parent="isl_ActivityThemeBase" tools:ignore="ResourceName">
<!-- Customize your theme here. -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
================================================
FILE: library/src/main/res/values-v23/dimens.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="isl_default_padding">16dp</dimen>
<!-- Target Activity View !-->
<dimen name="isl_target_activity_padding_vertical">16dp</dimen>
<dimen name="isl_target_activity_padding_horizontal">4dp</dimen>
<dimen name="isl_target_activity_view_icon_size">48dp</dimen>
<dimen name="isl_target_activity_icon_margin_left">0dp</dimen>
<dimen name="isl_target_activity_view_label_icon_margin">56dp</dimen>
<dimen name="isl_target_activity_header_view_font_size">19sp</dimen>
<dimen name="isl_target_activity_header_view_height">60dp</dimen>
<dimen name="isl_target_activity_view_height">120dp</dimen>
<dimen name="isl_target_activity_view_text_size">12sp</dimen>
<dimen name="isl_target_activity_recycler_padding">@dimen/isl_default_padding</dimen>
<dimen name="isl_target_activity_header_extra_padding">0dp</dimen>
</resources>
================================================
FILE: library/src/test/java/fr/tvbarthel/intentshare/IntentShareTest.java
================================================
package fr.tvbarthel.intentshare;
import android.content.Context;
import android.net.Uri;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static org.mockito.Mockito.mock;
/**
* Test for {@link IntentShare}
*/
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class IntentShareTest {
@Test
public void testTweetLimitEquals() throws Exception {
Context context = mock(Context.class);
String tweetLimitExceeded = "Tweet 140-character limit over exceeded with a "
+ "very very very very very very very very very very very very very"
+ "very ver"
+ "long text of 140 char";
Assert.assertEquals(140, tweetLimitExceeded.length());
IntentShare.with(context).twitterBody(tweetLimitExceeded);
}
@Test
public void testImageUriSupported() throws Exception {
Context context = mock(Context.class);
Uri image = Uri.parse("content://fr.tvbarthel.test.fileprovider/test.png");
IntentShare.with(context).image(image);
}
@Test(expected = IllegalArgumentException.class)
public void testImageUriSchemeNotSupported() throws Exception {
Context context = mock(Context.class);
Uri image = Uri.parse("http://tvbarthel.com/test.png");
IntentShare.with(context).image(image);
}
@Test(expected = IllegalArgumentException.class)
public void testImageUriExtensionNotSupported() throws Exception {
Context context = mock(Context.class);
Uri image = Uri.parse("content://fr.tvbarthel.test.fileprovider/test.html");
IntentShare.with(context).image(image);
}
@Test(expected = IllegalArgumentException.class)
public void testFacebookUriSchemeNotSupported() {
Context context = mock(Context.class);
Uri uri = Uri.parse("mailto://thomas.barthelemy.utc@gmail.com");
IntentShare.with(context).facebookBody(uri);
}
@Test
public void testFacebookURiSchemeSupported() {
Context context = mock(Context.class);
Uri uri = Uri.parse("http://www.tvbarthel.com");
IntentShare.with(context).facebookBody(uri);
}
}
================================================
FILE: picasso-loader/.gitignore
================================================
/build
================================================
FILE: picasso-loader/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
apply from: '../config/quality.gradle'
group = 'fr.tvbarthel.intentshare'
version = rootProject.ext.versionName
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.squareup.picasso:picasso:2.5.2'
compile project(':library')
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def bintrayUser = properties.getProperty('bintray.user')
def bintrayKey = properties.getProperty('bintray.apikey')
bintray {
user = bintrayUser
key = bintrayKey
configurations = ['archives'] //When uploading configuration files
dryRun = false //Whether to run this as dry-run, without deploying
publish = true //If version should be auto published after an upload
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'maven'
name = 'PicassoLoader'
desc = 'Icon loader based on Picasso for IntentShare library.'
websiteUrl = 'https://github.com/tvbarthel/IntentShare'
issueTrackerUrl = 'https://github.com/tvbarthel/IntentShare/issues'
vcsUrl = 'https://github.com/tvbarthel/IntentShare.git'
licenses = ['Apache-2.0']
labels = ['android', 'intent', 'sharing', 'share', 'picasso']
publicDownloadNumbers = true
version {
gpg {
sign = true //Determines whether to GPG sign the files. The default is false
}
}
}
}
install {
repositories.mavenInstaller {
pom {
project {
packaging 'aar'
name 'PicassoLoader'
url 'https://github.com/tvbarthel/IntentShare'
description 'Icon loader based on Picasso for IntentShare library.'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'tbarthel-fr'
name 'Thomas Barthelemy'
email 'thomas.barthelemy.utc@gmail.com'
}
developer {
id 'vbarthel-fr'
name 'Vincent Barthelemy'
email 'vincent.barthelemy.perso@gmail.com'
}
}
scm {
connection 'https://github.com/tvbarthel/IntentShare.git'
developerConnection 'https://github.com/tvbarthel/IntentShare.git'
url 'https://github.com/tvbarthel/IntentShare'
}
}
}
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
failOnError = false
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
================================================
FILE: picasso-loader/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/thomasbarthelemy/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: picasso-loader/src/main/AndroidManifest.xml
================================================
<manifest package="fr.tvbarthel.intentshare.loader.picasso">
<application />
</manifest>
================================================
FILE: picasso-loader/src/main/java/fr/tvbarthel/intentshare/loader/picasso/PicassoIconLoader.java
================================================
package fr.tvbarthel.intentshare.loader.picasso;
import android.net.Uri;
import android.os.Parcel;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import fr.tvbarthel.intentshare.IconLoader;
/**
* {@link IconLoader} based on {@link com.squareup.picasso.Picasso}.
*/
public class PicassoIconLoader implements IconLoader {
/**
* Parcelable.
*/
public static final Creator<PicassoIconLoader> CREATOR = new Creator<PicassoIconLoader>() {
@Override
public PicassoIconLoader createFromParcel(Parcel source) {
return new PicassoIconLoader(source);
}
@Override
public PicassoIconLoader[] newArray(int size) {
return new PicassoIconLoader[size];
}
};
/**
* {@link IconLoader} based on {@link com.squareup.picasso.Picasso}.
*/
public PicassoIconLoader() {
}
/**
* {@link IconLoader} based on {@link com.squareup.picasso.Picasso}.
*
* @param in parcel.
*/
protected PicassoIconLoader(Parcel in) {
}
@Override
public void load(Uri iconUri, ImageView imageView) {
Picasso.with(imageView.getContext())
.load(iconUri)
.fit()
.centerInside()
.into(imageView);
}
@Override
public void cancel(ImageView imageView) {
Picasso.with(imageView.getContext()).cancelRequest(imageView);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
}
================================================
FILE: sample/.gitignore
================================================
/build
================================================
FILE: sample/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "fr.tvbarthel.intentsharesample"
minSdkVersion 14
targetSdkVersion 25
versionCode 3
versionName "1.2"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:design:25.0.0'
compile project(':library')
compile project(':picasso-loader')
compile project(':glide-loader')
}
================================================
FILE: sample/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/thomas/Documents/android-sdk-linux/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: sample/src/androidTest/java/fr/tvbarthel/intentsharesample/ApplicationTest.java
================================================
package fr.tvbarthel.intentsharesample;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: sample/src/main/AndroidManifest.xml
================================================
<manifest package="fr.tvbarthel.intentsharesample"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="false"
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>
<!-- provider used to expose image through sharing intent!-->
<provider
android:name=".SharingFileProvider"
android:authorities="fr.tvbarthel.intentsharesample.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
</application>
</manifest>
================================================
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/Adapter.java
================================================
package fr.tvbarthel.intentsharesample;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
/**
* Simple adapter used to display the main content.
*/
class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private static final int VIEW_TYPE_HEADER = 1;
private static final int VIEW_TYPE_FOOTER = 2;
private static final int VIEW_TYPE_EXTRA_PROVIDER = 3;
private static final int HEADER_COUNT = 1;
private static final int FOOTER_COUNT = 1;
private final ArrayList<ExtraProviderWrapper> extraProviders;
private HeaderView.Listener internalHeaderListener;
private FooterView.Listener internalFooterListener;
private ExtraProviderWrapperView.Listener internalExtraProviderViewListener;
private Listener listener;
/**
* Simple adapter used to display the main content.
*
* @param extraProviders extra providers which must be listed for the user.
*/
public Adapter(ArrayList<ExtraProviderWrapper> extraProviders) {
this.extraProviders = extraProviders;
internalHeaderListener = new HeaderView.Listener() {
@Override
public void onLearMoreRequested() {
if (listener != null) {
listener.onLearMoreRequested();
}
}
@Override
public void onDialogTitleChanged(String dialogTitle) {
if (listener != null) {
listener.onDialogTitleChanged(dialogTitle);
}
}
@Override
public void onSharedTextChanged(String sharedText) {
if (listener != null) {
listener.onSharedTextChanged(sharedText);
}
}
@Override
public void onFacebookLinkChanged(String currentFacebookLink) {
if (listener != null) {
listener.onFacebookLinkChanged(currentFacebookLink);
}
}
@Override
public void onTweetChanged(String currentTweet) {
if (listener != null) {
listener.onTweetChanged(currentTweet);
}
}
@Override
public void onMailSubjectChanged(String currentMailSubject) {
if (listener != null) {
listener.onMailSubjectChanged(currentMailSubject);
}
}
@Override
public void onMailBodyChanged(String currentMailBody) {
if (listener != null) {
listener.onMailBodyChanged(currentMailBody);
}
}
};
internalFooterListener = new FooterView.Listener() {
@Override
public void onAddExtraProviderRequested() {
if (listener != null) {
listener.onAddExtraProviderRequested();
}
}
};
internalExtraProviderViewListener = new ExtraProviderWrapperView.Listener() {
@Override
public void onExtraProviderDetailRequested(ExtraProviderWrapper wrapper) {
if (listener != null) {
int wrapperPosition = Adapter.this.extraProviders.indexOf(wrapper);
listener.onExtraProviderDetailRequested(wrapperPosition, wrapper);
}
}
};
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_HEADER:
HeaderView headerView = new HeaderView(parent.getContext());
headerView.setListener(internalHeaderListener);
headerView.setLayoutParams(
new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
);
return new ViewHolder(headerView);
case VIEW_TYPE_FOOTER:
FooterView footerView = new FooterView(parent.getContext());
footerView.setListener(internalFooterListener);
footerView.setLayoutParams(
new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
);
return new ViewHolder(footerView);
default:
ExtraProviderWrapperView extraProviderView
= new ExtraProviderWrapperView(parent.getContext());
extraProviderView.setListener(internalExtraProviderViewListener);
extraProviderView.setLayoutParams(
new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
);
return new ViewHolder(extraProviderView);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (holder.getItemViewType() == VIEW_TYPE_EXTRA_PROVIDER) {
((ExtraProviderWrapperView) holder.itemView).presentData(extraProviders.get(position - HEADER_COUNT));
}
}
@Override
public int getItemCount() {
return extraProviders.size() + HEADER_COUNT + FOOTER_COUNT;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return VIEW_TYPE_HEADER;
} else if (position == getItemCount() - 1) {
return VIEW_TYPE_FOOTER;
} else {
return VIEW_TYPE_EXTRA_PROVIDER;
}
}
/**
* Listener used to catch adapted views events.
*
* @param listener Listener used to catch adapted views events.
*/
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Notify the adapter that an extra provider has been inserted at the end of the list.
*/
public void notifyExtraProviderInserted() {
notifyItemInserted(extraProviders.size() - 1 + HEADER_COUNT);
}
/**
* Notify the adapter that an extra provider has changed.
*
* @param position position of the extra provider in the list.
*/
public void notifyExtraProviderChanged(int position) {
notifyItemChanged(position + HEADER_COUNT);
}
/**
* View holder pattern.
*/
public final class ViewHolder extends RecyclerView.ViewHolder {
/**
* View holder pattern.
*
* @param itemView view to hold.
*/
public ViewHolder(View itemView) {
super(itemView);
}
}
/**
* Listener used to catch adapted views events.
*/
public interface Listener {
/**
* Called when the user wants to access to more information about the library.
*/
void onLearMoreRequested();
/**
* Called when the user wants to add an extra provider.
*/
void onAddExtraProviderRequested();
/**
* Called when the user update the dialog title.
*/
void onDialogTitleChanged(String dialogTitle);
/**
* Called when the user update the text to share.
*
* @param sharedText text to share.
*/
void onSharedTextChanged(String sharedText);
/**
* Called when the user change the link he wants to share on facebook.
*
* @param currentFacebookLink facebook link.
*/
void onFacebookLinkChanged(String currentFacebookLink);
/**
* Called when the user change the content of the tweet.
*
* @param currentTweet new tweet body.
*/
void onTweetChanged(String currentTweet);
/**
* Called when the user change the mail subject.
*
* @param currentMailSubject new mail subject.
*/
void onMailSubjectChanged(String currentMailSubject);
/**
* Called when the user change the mail body.
*
* @param currentMailBody new mail body.
*/
void onMailBodyChanged(String currentMailBody);
/**
* Called when the user wants to access to more detail for a given extra provider.
*/
void onExtraProviderDetailRequested(int wrapperPosition, ExtraProviderWrapper wrapper);
}
}
================================================
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/ExtraProviderDialogFragment.java
================================================
package fr.tvbarthel.intentsharesample;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ScrollView;
import fr.tvbarthel.intentshare.IntentShare;
/**
* Simple dialog used to edit an extra provider.
*/
public class ExtraProviderDialogFragment extends DialogFragment {
private static final String TAG = ExtraProviderDialogFragment.class.getSimpleName();
private static final String EXTRA_PROVIDER = "args_extra_provider";
private static final String EXTRA_POSITION = "args_extra_position";
/**
* Dummy callback used when fragment isn't attached.
*/
private static Callback dummyCallback = new Callback() {
@Override
public void onExtraProviderChanged(int position, ExtraProviderWrapper extraProviderWrapper) {
}
@Override
public void onExtraProviderCreated(ExtraProviderWrapper extraProviderWrapper) {
}
};
/**
* Current callback object.
*/
private Callback callback = dummyCallback;
/**
* Extra provider.
*/
private ExtraProviderWrapper extraProvider;
/**
* position of the extra provider.
*/
private int extraProviderPosition;
/**
* View components.
*/
private TextInputLayout appNameInputLayout;
private TextInputLayout packageNameInputLayout;
private EditText textEditText;
private EditText subjectEditText;
private CheckBox disableTextCheckBox;
private CheckBox disableSubjectCheckBox;
private CheckBox disableImageCheckBox;
/**
* Animation used to display emphasis on non valid field.
*/
private Animation wiggle;
private ScrollView scrollView;
/**
* Retrieve a new instnace to create a new extra provider.
*
* @return well instantiated instance.
*/
public static ExtraProviderDialogFragment newInstance() {
return newInstance(-1, null);
}
/**
* Retrieve a new instance for editing a given extra provider.
*
* @param position position of the extra provider inside the list.
* @param extraProviderWrapper extra provider to edit.
* @return well instantiated instance.
*/
public static ExtraProviderDialogFragment newInstance(
int position,
ExtraProviderWrapper extraProviderWrapper) {
ExtraProviderDialogFragment extraProviderDialogFragment = new ExtraProviderDialogFragment();
Bundle args = new Bundle();
args.putParcelable(EXTRA_PROVIDER, extraProviderWrapper);
args.putInt(EXTRA_POSITION, position);
extraProviderDialogFragment.setArguments(args);
return extraProviderDialogFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wiggle = AnimationUtils.loadAnimation(getContext(), R.anim.wiggle);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof Callback)) {
throw new IllegalStateException("Holding activity must implement the dialog callback.");
}
callback = ((Callback) activity);
extraProviderPosition = -1;
extraProvider = null;
Bundle args = getArguments();
if (args == null || !args.containsKey(EXTRA_POSITION) || !args.containsKey(EXTRA_PROVIDER)) {
throw new IllegalStateException("Required args missing, used new instance pattern.");
}
extraProviderPosition = args.getInt(EXTRA_POSITION);
extraProvider = args.getParcelable(EXTRA_PROVIDER);
}
@Override
public void onDetach() {
super.onDetach();
callback = dummyCallback;
}
/**
* Display the dialog to the user.
*
* @param fragmentManager fragment manager used to show the dialog.
*/
public void show(FragmentManager fragmentManager) {
this.show(fragmentManager, TAG);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View dialogView = LayoutInflater.from(getContext()).inflate(R.layout.fragment_dialog_extra_provider, null);
scrollView = ((ScrollView) dialogView.findViewById(R.id.fragment_dialog_extra_provider_scroll));
appNameInputLayout = ((TextInputLayout) dialogView.findViewById(R.id.fragment_dialog_extra_provider_app_name_input));
packageNameInputLayout = ((TextInputLayout) dialogView.findViewById(R.id.fragment_dialog_extra_provider_package_name_input));
textEditText = ((EditText) dialogView.findViewById(R.id.fragment_dialog_extra_provider_text));
subjectEditText = ((EditText) dialogView.findViewById(R.id.fragment_dialog_extra_provider_subject));
disableTextCheckBox = ((CheckBox) dialogView.findViewById(R.id.fragment_dialog_extra_provider_default_text_check));
disableSubjectCheckBox = ((CheckBox) dialogView.findViewById(R.id.fragment_dialog_extra_provider_default_subject_check));
disableImageCheckBox = ((CheckBox) dialogView.findViewById(R.id.fragment_dialog_extra_provider_default_image_check));
dialogView.findViewById(R.id.fragment_dialog_extra_provider_ok).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
processForm();
}
}
);
initializeView();
return new AlertDialog.Builder(getContext())
.setView(dialogView)
.setCancelable(true)
.create();
}
/**
* Initialize the dialog based on the passed extra provider.
*/
private void initializeView() {
if (extraProvider != null) {
IntentShare.ExtraProvider wrappedProvider = this.extraProvider.getExtraProvider();
appNameInputLayout.getEditText().setText(extraProvider.getAppName());
packageNameInputLayout.getEditText().setText(wrappedProvider.getPackageName());
textEditText.setText(wrappedProvider.getOverriddenText());
subjectEditText.setText(wrappedProvider.getOverriddenSubject());
disableTextCheckBox.setChecked(wrappedProvider.isTextDisabled());
disableSubjectCheckBox.setChecked(wrappedProvider.isSubjectDisabled());
disableImageCheckBox.setChecked(wrappedProvider.isImageDisabled());
}
}
/**
* Process the current form data.
*/
private void processForm() {
if (isFormValid()) {
IntentShare.ExtraProvider extraProvider = new IntentShare.ExtraProvider(
packageNameInputLayout.getEditText().getText().toString()
);
String text = textEditText.getText().toString();
if (!TextUtils.isEmpty(text)) {
extraProvider.overrideText(text);
}
String subject = subjectEditText.getText().toString();
if (!TextUtils.isEmpty(subject)) {
extraProvider.overrideSubject(subject);
}
if (disableTextCheckBox.isChecked()) {
extraProvider.disableText();
}
if (disableSubjectCheckBox.isChecked()) {
extraProvider.disableSubject();
}
if (disableImageCheckBox.isChecked()) {
extraProvider.disableImage();
}
if (extraProviderPosition != -1) {
callback.onExtraProviderChanged(
extraProviderPosition,
new ExtraProviderWrapper(
appNameInputLayout.getEditText().getText().toString(),
extraProvider
)
);
} else {
callback.onExtraProviderCreated(new ExtraProviderWrapper(
appNameInputLayout.getEditText().getText().toString(),
extraProvider
)
);
}
dismiss();
}
}
/**
* Used to check if the form is well field.
*
* @return true if the farm is valid, false otherwise.
*/
private boolean isFormValid() {
return isEditTextValid(appNameInputLayout) && isEditTextValid(packageNameInputLayout);
}
/**
* Used to check if an {@link EditText} is not empty.
*
* @param inputLayout layout containing an edit text which musn't be empty.
* @return true if the edit text is not empty.
*/
private boolean isEditTextValid(@NonNull TextInputLayout inputLayout) {
EditText editText = inputLayout.getEditText();
String text = editText.getText().toString();
boolean empty = TextUtils.isEmpty(text);
if (empty) {
inputLayout.startAnimation(wiggle);
scrollView.smoothScrollTo(0, inputLayout.getTop());
}
return !empty;
}
/**
* Callback used to catch fragment events.
*/
public interface Callback {
/**
* Called when the extra provider at the given position index has changed.
*
* @param position position passed.
* @param extraProviderWrapper extra provider wrapper.
*/
void onExtraProviderChanged(int position, ExtraProviderWrapper extraProviderWrapper);
/**
* Called when the user create a new extra provider.
*
* @param extraProviderWrapper new extra provider created.
*/
void onExtraProviderCreated(ExtraProviderWrapper extraProviderWrapper);
}
}
================================================
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/ExtraProviderWrapper.java
================================================
package fr.tvbarthel.intentsharesample;
import android.os.Parcel;
import android.os.Parcelable;
import fr.tvbarthel.intentshare.IntentShare;
/**
* Encapsulate data around an {@link ExtraProviderWrapper}
*/
class ExtraProviderWrapper implements Parcelable {
/**
* Parcelable.
*/
public static final Parcelable.Creator<ExtraProviderWrapper> CREATOR
= new Parcelable.Creator<ExtraProviderWrapper>() {
@Override
public ExtraProviderWrapper createFromParcel(Parcel source) {
return new ExtraProviderWrapper(source);
}
@Override
public ExtraProviderWrapper[] newArray(int size) {
return new ExtraProviderWrapper[size];
}
};
private String appName;
private IntentShare.ExtraProvider extraProvider;
/**
* Encapsulate data around an {@link ExtraProviderWrapper}
*
* @param appName name of the app for which the extra provider has been build.
*/
public ExtraProviderWrapper(String appName, IntentShare.ExtraProvider extraProvider) {
this.appName = appName;
this.extraProvider = extraProvider;
}
/**
* Encapsulate data around an {@
gitextract_wcsb18mc/ ├── .gitignore ├── README.md ├── build.gradle ├── config/ │ ├── quality/ │ │ ├── checkstyle/ │ │ │ ├── checkstyle.xml │ │ │ └── suppressions.xml │ │ ├── findbugs/ │ │ │ └── findbugs-filter.xml │ │ ├── lint/ │ │ │ └── lint.xml │ │ └── pmd/ │ │ └── pmd-ruleset.xml │ └── quality.gradle ├── glide-loader/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── fr/ │ └── tvbarthel/ │ └── intentshare/ │ └── loader/ │ └── glide/ │ └── GlideIconLoader.java ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── fr/ │ │ └── tvbarthel/ │ │ └── intentshare/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── fr/ │ │ │ └── tvbarthel/ │ │ │ └── intentshare/ │ │ │ ├── AsyncIconLoader.java │ │ │ ├── BottomRecyclerView.java │ │ │ ├── IconLoader.java │ │ │ ├── IntentShare.java │ │ │ ├── IntentShareListener.java │ │ │ ├── LayoutManagerFactory.java │ │ │ ├── StyledAttributesUtils.java │ │ │ ├── TargetActivity.java │ │ │ ├── TargetActivityAdapter.java │ │ │ ├── TargetActivityComparatorProvider.java │ │ │ ├── TargetActivityHeaderView.java │ │ │ ├── TargetActivityManager.java │ │ │ ├── TargetActivityView.java │ │ │ └── TargetChooserActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── isl_activity_target_chooser.xml │ │ │ └── isl_target_activity_view.xml │ │ ├── layout-v23/ │ │ │ └── isl_target_activity_view.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── public.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v19/ │ │ │ └── styles.xml │ │ └── values-v23/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── fr/ │ └── tvbarthel/ │ └── intentshare/ │ └── IntentShareTest.java ├── picasso-loader/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── fr/ │ └── tvbarthel/ │ └── intentshare/ │ └── loader/ │ └── picasso/ │ └── PicassoIconLoader.java ├── sample/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── fr/ │ │ └── tvbarthel/ │ │ └── intentsharesample/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── fr/ │ │ │ └── tvbarthel/ │ │ │ └── intentsharesample/ │ │ │ ├── Adapter.java │ │ │ ├── ExtraProviderDialogFragment.java │ │ │ ├── ExtraProviderWrapper.java │ │ │ ├── ExtraProviderWrapperView.java │ │ │ ├── FooterView.java │ │ │ ├── HeaderView.java │ │ │ ├── MainActivity.java │ │ │ ├── SharingFileProvider.java │ │ │ └── SocialTargetActivityComparatorProvider.java │ │ └── res/ │ │ ├── anim/ │ │ │ └── wiggle.xml │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── extra_provider_view.xml │ │ │ ├── footer_view.xml │ │ │ ├── fragment_dialog_extra_provider.xml │ │ │ └── header_view.xml │ │ ├── menu/ │ │ │ └── activity_sample_menu.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-w820dp/ │ │ │ └── dimens.xml │ │ └── xml/ │ │ └── file_provider_paths.xml │ └── test/ │ └── java/ │ └── fr/ │ └── tvbarthel/ │ └── intentsharesample/ │ └── ExampleUnitTest.java └── settings.gradle
SYMBOL INDEX (318 symbols across 29 files)
FILE: glide-loader/src/main/java/fr/tvbarthel/intentshare/loader/glide/GlideIconLoader.java
class GlideIconLoader (line 15) | public class GlideIconLoader implements IconLoader {
method createFromParcel (line 21) | @Override
method newArray (line 26) | @Override
method GlideIconLoader (line 35) | public GlideIconLoader() {
method GlideIconLoader (line 43) | protected GlideIconLoader(Parcel in) {
method load (line 46) | @Override
method cancel (line 55) | @Override
method describeContents (line 60) | @Override
method writeToParcel (line 65) | @Override
FILE: library/src/androidTest/java/fr/tvbarthel/intentshare/ApplicationTest.java
class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
method ApplicationTest (line 10) | public ApplicationTest() {
FILE: library/src/main/java/fr/tvbarthel/intentshare/AsyncIconLoader.java
class AsyncIconLoader (line 22) | class AsyncIconLoader implements IconLoader {
method createFromParcel (line 28) | @Override
method newArray (line 33) | @Override
method AsyncIconLoader (line 49) | protected AsyncIconLoader(Parcel in) {
method AsyncIconLoader (line 58) | public AsyncIconLoader() {
method describeContents (line 63) | @Override
method writeToParcel (line 68) | @Override
method load (line 72) | @Override
method cancel (line 85) | @Override
class AsyncIconLoaderTask (line 98) | private static final class AsyncIconLoaderTask extends AsyncTask<Void,...
method AsyncIconLoaderTask (line 117) | public AsyncIconLoaderTask(Uri uri, ImageView imageView, HashMap<Uri...
method doInBackground (line 140) | @Override
method onPostExecute (line 173) | @Override
method calculateInSampleSize (line 184) | private int calculateInSampleSize(
FILE: library/src/main/java/fr/tvbarthel/intentshare/BottomRecyclerView.java
class BottomRecyclerView (line 12) | class BottomRecyclerView extends RecyclerView {
method BottomRecyclerView (line 19) | public BottomRecyclerView(Context context) {
method BottomRecyclerView (line 29) | public BottomRecyclerView(Context context, AttributeSet attrs) {
method BottomRecyclerView (line 40) | public BottomRecyclerView(Context context, AttributeSet attrs, int def...
method onTouchEvent (line 44) | @Override
FILE: library/src/main/java/fr/tvbarthel/intentshare/IconLoader.java
type IconLoader (line 11) | public interface IconLoader extends Parcelable {
method load (line 21) | void load(Uri iconUri, ImageView imageView);
method cancel (line 31) | void cancel(ImageView imageView);
FILE: library/src/main/java/fr/tvbarthel/intentshare/IntentShare.java
class IntentShare (line 16) | public final class IntentShare implements Parcelable {
method createFromParcel (line 22) | public IntentShare createFromParcel(Parcel source) {
method newArray (line 26) | public IntentShare[] newArray(int size) {
method IntentShare (line 101) | private IntentShare(Context context) {
method IntentShare (line 117) | protected IntentShare(Parcel in) {
method describeContents (line 128) | @Override
method writeToParcel (line 133) | @Override
method with (line 152) | @NonNull
method chooserTitle (line 165) | public IntentShare chooserTitle(@NonNull String title) {
method iconLoader (line 176) | public IntentShare iconLoader(@NonNull IconLoader iconLoader) {
method comparatorProvider (line 193) | public IntentShare comparatorProvider(@NonNull TargetActivityComparato...
method text (line 209) | @NonNull
method image (line 222) | @NonNull
method mailBody (line 246) | @NonNull
method mailSubject (line 261) | @NonNull
method facebookBody (line 276) | @NonNull
method twitterBody (line 310) | @NonNull
method listener (line 332) | public IntentShare listener(@NonNull IntentShareListener listener) {
method addExtraProvider (line 343) | public IntentShare addExtraProvider(@NonNull ExtraProvider extraProvid...
method deliver (line 360) | public void deliver() {
class ExtraProvider (line 370) | public static class ExtraProvider implements Parcelable {
method createFromParcel (line 376) | @Override
method newArray (line 381) | @Override
method ExtraProvider (line 433) | public ExtraProvider(String packageName) {
method ExtraProvider (line 455) | protected ExtraProvider(Parcel in) {
method equals (line 465) | @Override
method hashCode (line 502) | @Override
method describeContents (line 514) | @Override
method writeToParcel (line 519) | @Override
method overrideText (line 536) | public ExtraProvider overrideText(String text) {
method overrideSubject (line 547) | public ExtraProvider overrideSubject(String subject) {
method overrideImage (line 558) | public ExtraProvider overrideImage(Uri image) {
method disableText (line 569) | public ExtraProvider disableText() {
method disableSubject (line 580) | public ExtraProvider disableSubject() {
method disableImage (line 591) | public ExtraProvider disableImage() {
method getPackageName (line 601) | public String getPackageName() {
method getOverriddenText (line 610) | public String getOverriddenText() {
method getOverriddenSubject (line 619) | public String getOverriddenSubject() {
method getOverriddenImage (line 628) | public Uri getOverriddenImage() {
method isTextDisabled (line 637) | public boolean isTextDisabled() {
method isSubjectDisabled (line 646) | public boolean isSubjectDisabled() {
method isImageDisabled (line 655) | public boolean isImageDisabled() {
FILE: library/src/main/java/fr/tvbarthel/intentshare/IntentShareListener.java
class IntentShareListener (line 12) | public abstract class IntentShareListener {
method IntentShareListener (line 37) | public IntentShareListener() {
method onCompleted (line 59) | public abstract void onCompleted(String packageName);
method onCanceled (line 64) | public abstract void onCanceled();
method notifySharingCompleted (line 74) | static void notifySharingCompleted(Context context, String packageName) {
method notifySharingCanceled (line 87) | static void notifySharingCanceled(Context context) {
method register (line 99) | void register(Context context) {
class InternalReceiver (line 110) | private static class InternalReceiver extends BroadcastReceiver {
method onReceive (line 112) | @Override
method onCompleted (line 134) | public void onCompleted(String packageName) {
method onCanceled (line 141) | public void onCanceled() {
FILE: library/src/main/java/fr/tvbarthel/intentshare/LayoutManagerFactory.java
class LayoutManagerFactory (line 12) | final class LayoutManagerFactory {
method LayoutManagerFactory (line 19) | private LayoutManagerFactory() {
method buildLayoutManager (line 30) | public static RecyclerView.LayoutManager buildLayoutManager(Context co...
class MarshmallowSpanSizeLookup (line 44) | private static final class MarshmallowSpanSizeLookup extends GridLayou...
method getSpanSize (line 46) | @Override
FILE: library/src/main/java/fr/tvbarthel/intentshare/StyledAttributesUtils.java
class StyledAttributesUtils (line 10) | final class StyledAttributesUtils {
method StyledAttributesUtils (line 15) | private StyledAttributesUtils() {
method getSelectableItemBackground (line 25) | public static int getSelectableItemBackground(Context context) {
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivity.java
class TargetActivity (line 14) | public class TargetActivity {
method TargetActivity (line 30) | public TargetActivity(Context context, ResolveInfo resolveInfo, long l...
method equals (line 49) | @Override
method hashCode (line 63) | @Override
method getId (line 75) | public String getId() {
method getPackageName (line 85) | public String getPackageName() {
method getActivityName (line 94) | public String getActivityName() {
method getActivityLabelResId (line 103) | public int getActivityLabelResId() {
method getIconUri (line 112) | public Uri getIconUri() {
method isMailClient (line 123) | public boolean isMailClient() {
method getLastSelection (line 133) | public long getLastSelection() {
method getLabel (line 142) | CharSequence getLabel() {
method getResolveInfo (line 151) | ResolveInfo getResolveInfo() {
method setLabel (line 160) | void setLabel(CharSequence label) {
class RecencyComparatorProvider (line 172) | public static final class RecencyComparatorProvider implements TargetA...
method createFromParcel (line 178) | @Override
method newArray (line 183) | @Override
method RecencyComparatorProvider (line 197) | public RecencyComparatorProvider() {
method RecencyComparatorProvider (line 211) | protected RecencyComparatorProvider(Parcel in) {
method provideComparator (line 216) | @Override
method describeContents (line 237) | @Override
method writeToParcel (line 242) | @Override
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityAdapter.java
class TargetActivityAdapter (line 12) | class TargetActivityAdapter extends RecyclerView.Adapter<TargetActivityA...
method TargetActivityAdapter (line 45) | public TargetActivityAdapter(final List<TargetActivity> targetActivities,
method onCreateViewHolder (line 61) | @Override
method onBindViewHolder (line 94) | @Override
method onViewRecycled (line 112) | @Override
method getItemCount (line 120) | @Override
method getItemViewType (line 126) | @Override
method setListener (line 140) | public void setListener(Listener listener) {
method notifyTargetActivityChanged (line 149) | public void notifyTargetActivityChanged(TargetActivity targetActivity) {
class ViewHolder (line 159) | public class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 166) | public ViewHolder(TargetActivityView itemView) {
method ViewHolder (line 175) | public ViewHolder(TargetActivityHeaderView headerView) {
type Listener (line 183) | public interface Listener {
method onTargetActivitySelected (line 189) | void onTargetActivitySelected(TargetActivity targetActivity);
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityComparatorProvider.java
type TargetActivityComparatorProvider (line 11) | public interface TargetActivityComparatorProvider extends Parcelable {
method provideComparator (line 18) | Comparator<TargetActivity> provideComparator();
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityHeaderView.java
class TargetActivityHeaderView (line 14) | class TargetActivityHeaderView extends TextView {
method TargetActivityHeaderView (line 26) | public TargetActivityHeaderView(Context context) {
method TargetActivityHeaderView (line 36) | public TargetActivityHeaderView(Context context, AttributeSet attrs) {
method TargetActivityHeaderView (line 47) | public TargetActivityHeaderView(Context context, AttributeSet attrs, i...
method onMeasure (line 54) | @Override
method setModel (line 64) | public void setModel(String label) {
method initialize (line 73) | private void initialize(Context context) {
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityManager.java
class TargetActivityManager (line 22) | class TargetActivityManager {
method TargetActivityManager (line 49) | public TargetActivityManager() {
method resolveTargetActivities (line 63) | public void resolveTargetActivities(Context context, ResolveListener l...
method getLastSelectionKey (line 106) | private String getLastSelectionKey(String packageName, String activity...
method startTargetActivity (line 117) | public void startTargetActivity(Context context, TargetActivity target...
method buildTargetActivityIntent (line 145) | private Intent buildTargetActivityIntent(TargetActivity targetActivity...
method applyExtraProvider (line 174) | private void applyExtraProvider(
method addImageExtras (line 208) | private void addImageExtras(Intent intent, Uri imageUri) {
type ResolveListener (line 219) | public interface ResolveListener {
method onTargetActivitiesResolved (line 230) | void onTargetActivitiesResolved(@NonNull ArrayList<TargetActivity> t...
method onLabelResolved (line 237) | void onLabelResolved(@NonNull TargetActivity targetActivity);
class AsyncLabelLoader (line 244) | private static final class AsyncLabelLoader extends AsyncTask<Void, Vo...
method AsyncLabelLoader (line 257) | public AsyncLabelLoader(
method doInBackground (line 266) | @Override
method onPostExecute (line 271) | @Override
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetActivityView.java
class TargetActivityView (line 16) | class TargetActivityView extends FrameLayout {
method TargetActivityView (line 32) | public TargetActivityView(Context context, IconLoader asyncIconLoader) {
method TargetActivityView (line 46) | public TargetActivityView(Context context, AttributeSet attrs) {
method TargetActivityView (line 60) | public TargetActivityView(Context context, AttributeSet attrs, int def...
method onMeasure (line 67) | @Override
method setModel (line 77) | public void setModel(TargetActivity model) {
method setListener (line 87) | public void setListener(Listener listener) {
method loadIcon (line 94) | public void loadIcon() {
method cancelIconLoading (line 102) | public void cancelIconLoading() {
method initialize (line 111) | private void initialize(Context context) {
type Listener (line 147) | public interface Listener {
method onTargetActivitySelected (line 154) | void onTargetActivitySelected(TargetActivity targetActivity);
FILE: library/src/main/java/fr/tvbarthel/intentshare/TargetChooserActivity.java
class TargetChooserActivity (line 25) | public class TargetChooserActivity extends AppCompatActivity
method start (line 141) | public static void start(Context context, IntentShare intentShare) {
method onCreate (line 151) | @Override
method onBackPressed (line 190) | @Override
method onSaveInstanceState (line 195) | @Override
method onDestroy (line 201) | @Override
method finish (line 209) | @Override
method onClick (line 220) | @Override
method onTargetActivitiesResolved (line 225) | @Override
method onTargetActivitySelected (line 231) | @Override
method onLabelResolved (line 238) | @Override
method setUpRecyclerView (line 244) | private void setUpRecyclerView(Bundle savedInstance) {
method setUpStickyTitle (line 327) | private void setUpStickyTitle() {
method finishAnimated (line 334) | private void finishAnimated() {
FILE: library/src/test/java/fr/tvbarthel/intentshare/IntentShareTest.java
class IntentShareTest (line 18) | @RunWith(RobolectricTestRunner.class)
method testTweetLimitEquals (line 22) | @Test
method testImageUriSupported (line 33) | @Test
method testImageUriSchemeNotSupported (line 40) | @Test(expected = IllegalArgumentException.class)
method testImageUriExtensionNotSupported (line 47) | @Test(expected = IllegalArgumentException.class)
method testFacebookUriSchemeNotSupported (line 54) | @Test(expected = IllegalArgumentException.class)
method testFacebookURiSchemeSupported (line 61) | @Test
FILE: picasso-loader/src/main/java/fr/tvbarthel/intentshare/loader/picasso/PicassoIconLoader.java
class PicassoIconLoader (line 14) | public class PicassoIconLoader implements IconLoader {
method createFromParcel (line 20) | @Override
method newArray (line 25) | @Override
method PicassoIconLoader (line 34) | public PicassoIconLoader() {
method PicassoIconLoader (line 42) | protected PicassoIconLoader(Parcel in) {
method load (line 45) | @Override
method cancel (line 54) | @Override
method describeContents (line 59) | @Override
method writeToParcel (line 64) | @Override
FILE: sample/src/androidTest/java/fr/tvbarthel/intentsharesample/ApplicationTest.java
class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
method ApplicationTest (line 10) | public ApplicationTest() {
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/Adapter.java
class Adapter (line 12) | class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
method Adapter (line 33) | public Adapter(ArrayList<ExtraProviderWrapper> extraProviders) {
method onCreateViewHolder (line 104) | @Override
method onBindViewHolder (line 142) | @Override
method getItemCount (line 149) | @Override
method getItemViewType (line 154) | @Override
method setListener (line 170) | public void setListener(Listener listener) {
method notifyExtraProviderInserted (line 177) | public void notifyExtraProviderInserted() {
method notifyExtraProviderChanged (line 186) | public void notifyExtraProviderChanged(int position) {
class ViewHolder (line 193) | public final class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 200) | public ViewHolder(View itemView) {
type Listener (line 208) | public interface Listener {
method onLearMoreRequested (line 213) | void onLearMoreRequested();
method onAddExtraProviderRequested (line 218) | void onAddExtraProviderRequested();
method onDialogTitleChanged (line 223) | void onDialogTitleChanged(String dialogTitle);
method onSharedTextChanged (line 230) | void onSharedTextChanged(String sharedText);
method onFacebookLinkChanged (line 237) | void onFacebookLinkChanged(String currentFacebookLink);
method onTweetChanged (line 244) | void onTweetChanged(String currentTweet);
method onMailSubjectChanged (line 251) | void onMailSubjectChanged(String currentMailSubject);
method onMailBodyChanged (line 258) | void onMailBodyChanged(String currentMailBody);
method onExtraProviderDetailRequested (line 263) | void onExtraProviderDetailRequested(int wrapperPosition, ExtraProvid...
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/ExtraProviderDialogFragment.java
class ExtraProviderDialogFragment (line 25) | public class ExtraProviderDialogFragment extends DialogFragment {
method onExtraProviderChanged (line 35) | @Override
method onExtraProviderCreated (line 40) | @Override
method newInstance (line 83) | public static ExtraProviderDialogFragment newInstance() {
method newInstance (line 94) | public static ExtraProviderDialogFragment newInstance(
method onCreate (line 105) | @Override
method onAttach (line 111) | @Override
method onDetach (line 132) | @Override
method show (line 143) | public void show(FragmentManager fragmentManager) {
method onCreateDialog (line 147) | @NonNull
method initializeView (line 182) | private void initializeView() {
method processForm (line 198) | private void processForm() {
method isFormValid (line 250) | private boolean isFormValid() {
method isEditTextValid (line 260) | private boolean isEditTextValid(@NonNull TextInputLayout inputLayout) {
type Callback (line 275) | public interface Callback {
method onExtraProviderChanged (line 282) | void onExtraProviderChanged(int position, ExtraProviderWrapper extra...
method onExtraProviderCreated (line 289) | void onExtraProviderCreated(ExtraProviderWrapper extraProviderWrapper);
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/ExtraProviderWrapper.java
class ExtraProviderWrapper (line 11) | class ExtraProviderWrapper implements Parcelable {
method createFromParcel (line 18) | @Override
method newArray (line 23) | @Override
method ExtraProviderWrapper (line 37) | public ExtraProviderWrapper(String appName, IntentShare.ExtraProvider ...
method ExtraProviderWrapper (line 47) | protected ExtraProviderWrapper(Parcel in) {
method describeContents (line 52) | @Override
method writeToParcel (line 57) | @Override
method equals (line 63) | @Override
method hashCode (line 81) | @Override
method getAppName (line 93) | public String getAppName() {
method getExtraProvider (line 102) | public IntentShare.ExtraProvider getExtraProvider() {
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/ExtraProviderWrapperView.java
class ExtraProviderWrapperView (line 13) | class ExtraProviderWrapperView extends FrameLayout {
method ExtraProviderWrapperView (line 24) | public ExtraProviderWrapperView(Context context) {
method ExtraProviderWrapperView (line 34) | public ExtraProviderWrapperView(Context context, AttributeSet attrs) {
method ExtraProviderWrapperView (line 45) | public ExtraProviderWrapperView(Context context, AttributeSet attrs, i...
method presentData (line 55) | public void presentData(ExtraProviderWrapper extraProviderWrapper) {
method setListener (line 65) | public void setListener(Listener listener) {
method initialize (line 74) | private void initialize(Context context) {
type Listener (line 90) | public interface Listener {
method onExtraProviderDetailRequested (line 95) | void onExtraProviderDetailRequested(ExtraProviderWrapper wrapper);
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/FooterView.java
class FooterView (line 12) | class FooterView extends FrameLayout {
method FooterView (line 21) | public FooterView(Context context) {
method FooterView (line 31) | public FooterView(Context context, AttributeSet attrs) {
method FooterView (line 42) | public FooterView(Context context, AttributeSet attrs, int defStyleAtt...
method setListener (line 52) | public void setListener(Listener listener) {
method initialize (line 61) | private void initialize(Context context) {
type Listener (line 76) | public interface Listener {
method onAddExtraProviderRequested (line 80) | void onAddExtraProviderRequested();
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/HeaderView.java
class HeaderView (line 16) | class HeaderView extends LinearLayout {
method HeaderView (line 33) | public HeaderView(Context context) {
method HeaderView (line 43) | public HeaderView(Context context, AttributeSet attrs) {
method HeaderView (line 54) | public HeaderView(Context context, AttributeSet attrs, int defStyleAtt...
method setListener (line 64) | public void setListener(Listener listener) {
method initialize (line 79) | private void initialize(Context context) {
method initializeMail (line 114) | private void initializeMail(Context context) {
method initializeTweetLink (line 161) | private void initializeTweetLink(Context context) {
method initializeFacebookLink (line 190) | private void initializeFacebookLink(Context context) {
method initializeSharedText (line 215) | private void initializeSharedText(Context context) {
method initializeDialogTitle (line 240) | private void initializeDialogTitle(Context context) {
type Listener (line 268) | public interface Listener {
method onLearMoreRequested (line 273) | void onLearMoreRequested();
method onDialogTitleChanged (line 278) | void onDialogTitleChanged(String dialogTitle);
method onSharedTextChanged (line 285) | void onSharedTextChanged(String sharedText);
method onFacebookLinkChanged (line 292) | void onFacebookLinkChanged(String currentFacebookLink);
method onTweetChanged (line 299) | void onTweetChanged(String currentTweet);
method onMailSubjectChanged (line 306) | void onMailSubjectChanged(String currentMailSubject);
method onMailBodyChanged (line 313) | void onMailBodyChanged(String currentMailBody);
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/MainActivity.java
class MainActivity (line 33) | public class MainActivity extends AppCompatActivity implements
method onCreate (line 67) | @Override
method onResume (line 92) | @Override
method onCreateOptionsMenu (line 101) | @Override
method onOptionsItemSelected (line 108) | @Override
method onLearMoreRequested (line 140) | @Override
method onAddExtraProviderRequested (line 147) | @Override
method onDialogTitleChanged (line 152) | @Override
method onSharedTextChanged (line 157) | @Override
method onFacebookLinkChanged (line 162) | @Override
method onTweetChanged (line 167) | @Override
method onMailSubjectChanged (line 172) | @Override
method onMailBodyChanged (line 177) | @Override
method onExtraProviderDetailRequested (line 182) | @Override
method onExtraProviderChanged (line 187) | @Override
method onExtraProviderCreated (line 194) | @Override
method onClick (line 201) | @Override
method setUpRecyclerView (line 224) | private void setUpRecyclerView() {
method buildPocketProvider (line 243) | private ExtraProviderWrapper buildPocketProvider() {
method buildKeepProvider (line 258) | private ExtraProviderWrapper buildKeepProvider() {
method getShareableUri (line 266) | private Uri getShareableUri(Context context, Bitmap bitmap) {
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/SharingFileProvider.java
class SharingFileProvider (line 24) | public class SharingFileProvider extends FileProvider {
method query (line 26) | @Override
method isMediaStoreOrientationProjection (line 41) | private boolean isMediaStoreOrientationProjection(String[] projection) {
method queryMediaStoreOrientation (line 50) | private Cursor queryMediaStoreOrientation() {
FILE: sample/src/main/java/fr/tvbarthel/intentsharesample/SocialTargetActivityComparatorProvider.java
class SocialTargetActivityComparatorProvider (line 18) | class SocialTargetActivityComparatorProvider implements TargetActivityCo...
method createFromParcel (line 27) | @Override
method newArray (line 32) | @Override
method SocialTargetActivityComparatorProvider (line 45) | public SocialTargetActivityComparatorProvider() {
method SocialTargetActivityComparatorProvider (line 70) | protected SocialTargetActivityComparatorProvider(Parcel in) {
method provideComparator (line 76) | @Override
method describeContents (line 96) | @Override
method writeToParcel (line 101) | @Override
FILE: sample/src/test/java/fr/tvbarthel/intentsharesample/ExampleUnitTest.java
class ExampleUnitTest (line 10) | public class ExampleUnitTest {
method addition_isCorrect (line 11) | @Test
Condensed preview — 82 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (262K chars).
[
{
"path": ".gitignore",
"chars": 1464,
"preview": "# Created by https://www.gitignore.io\n\n### Android ###\n# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n"
},
{
"path": "README.md",
"chars": 10844,
"preview": "IntentShare\n==================\n\n[
About this extraction
This page contains the full source code of the tvbarthel/IntentShare GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 82 files (240.4 KB), approximately 55.0k tokens, and a symbol index with 318 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.