Skip to content

Commit

Permalink
Issue mozilla-mobile#494: Add browser-icon module and icons code
Browse files Browse the repository at this point in the history
  • Loading branch information
jonalmeida committed Nov 5, 2018
1 parent 7fced7a commit c10f15b
Show file tree
Hide file tree
Showing 69 changed files with 6,892 additions and 2 deletions.
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Dependencies.kt
Expand Up @@ -49,6 +49,7 @@ object Deps {
const val support_fragment = "com.android.support:support-fragment:${Versions.support_libraries}"
const val support_constraintlayout = "com.android.support.constraint:constraint-layout:${Versions.constraint_layout}"
const val support_compat = "com.android.support:support-compat:${Versions.support_libraries}"
const val support_palette = "com.android.support:palette-v7:${Versions.support_libraries}"

const val arch_workmanager = "android.arch.work:work-runtime:${Versions.workmanager}"

Expand Down
23 changes: 23 additions & 0 deletions components/browser/icons/README.md
@@ -0,0 +1,23 @@
# [Android Components](../../../README.md) > Browser > Icons

Favicons support for Android browser apps.

## Usage

### Setting up the dependency

Use gradle to download the library from JCenter:

```Groovy
implementation "org.mozilla.components:browser-icons:{latest-version}"
```
### Quick Start

(TBD)

## License

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/

61 changes: 61 additions & 0 deletions components/browser/icons/build.gradle
@@ -0,0 +1,61 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion Config.compileSdkVersion

defaultConfig {
minSdkVersion Config.minSdkVersion
targetSdkVersion Config.targetSdkVersion

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

lintOptions {
// Lint reports (falsely) a bunch of unused resources for this project. Those resources
// are references from Kotlin code and it looks like Android lint can't see those references
// yet. Let's disable this check and retry once a newer SDK is available.
disable 'UnusedResources'
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

}

dependencies {
implementation project(':support-ktx')
implementation project(':support-base')
implementation project(':support-utils')

implementation Deps.support_annotations
implementation Deps.kotlin_stdlib

testImplementation project(':support-test')

testImplementation Deps.testing_junit
testImplementation Deps.testing_robolectric
testImplementation Deps.testing_mockito
}

archivesBaseName = "icons"

apply from: '../../../publish.gradle'
ext.configurePublish(
'org.mozilla.components',
'icons',
'Favicons support for Android browser apps.')
21 changes: 21 additions & 0 deletions components/browser/icons/proguard-rules.pro
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# 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 *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
5 changes: 5 additions & 0 deletions components/browser/icons/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mozilla.components.browser.icons" />
@@ -0,0 +1,25 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mozilla.components.browser.icons;

/**
* Interface for a callback that will be executed once an icon has been loaded successfully.
*/
public interface IconCallback {
void onIconResponse(IconResponse response);
}
@@ -0,0 +1,125 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mozilla.components.browser.icons;

import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;

/**
* A class describing the location and properties of an icon that can be loaded.
*/
public class IconDescriptor {
@IntDef({ TYPE_GENERIC, TYPE_FAVICON, TYPE_TOUCHICON, TYPE_LOOKUP, TYPE_BUNDLED_TILE })
@interface IconType {}

// The type values are used for ranking icons (higher values = try to load first).
@VisibleForTesting
static final int TYPE_GENERIC = 0;
@VisibleForTesting
static final int TYPE_LOOKUP = 1;
@VisibleForTesting
static final int TYPE_FAVICON = 5;
@VisibleForTesting
static final int TYPE_TOUCHICON = 10;
@VisibleForTesting
static final int TYPE_BUNDLED_TILE = 15;

private final String url;
private final int size;
private final String mimeType;
private final int type;

/**
* Create a generic icon located at the given URL. No MIME type or size is known.
*/
public static IconDescriptor createGenericIcon(@NonNull String url) {
return new IconDescriptor(TYPE_GENERIC, url, 0, null);
}

/**
* Create a favicon located at the given URL and with a known size and MIME type.
*/
public static IconDescriptor createFavicon(@NonNull String url, int size, String mimeType) {
return new IconDescriptor(TYPE_FAVICON, url, size, mimeType);
}

/**
* Create a touch icon located at the given URL and with a known MIME type and size.
*/
public static IconDescriptor createTouchicon(@NonNull String url, int size, String mimeType) {
return new IconDescriptor(TYPE_TOUCHICON, url, size, mimeType);
}

/**
* Create an icon located at an URL that has been returned from a disk or memory storage. This
* is an icon with an URL we loaded an icon from previously. Therefore we give it a little higher
* ranking than a generic icon - even though we do not know the MIME type or size of the icon.
*/
public static IconDescriptor createLookupIcon(@NonNull String url) {
return new IconDescriptor(TYPE_LOOKUP, url, 0, null);
}

/**
* Create a bundled tile icon at the given URL. MIME type or size is not known until we load
* the icons, but we know these icons are high fidelity. (Although the icons are png's at time
* of writing, they could be changed to webp or VectorDrawable in future.)
*/
public static IconDescriptor createBundledTileIcon(@NonNull String url) {
return new IconDescriptor(TYPE_BUNDLED_TILE, url, 0, null);
}


private IconDescriptor(@IconType int type, @NonNull String url, int size, String mimeType) {
this.type = type;
this.url = url;
this.size = size;
this.mimeType = mimeType;
}

/**
* Get the URL of the icon.
*/
public String getUrl() {
return url;
}

/**
* Get the (assumed) size of the icon. Returns 0 if no size is known.
*/
public int getSize() {
return size;
}

/**
* Get the type of the icon (favicon, touch icon, generic, lookup).
*/
@IconType
public int getType() {
return type;
}

/**
* Get the (assumed) MIME type of the icon. Returns null if no MIME type is known.
*/
@Nullable
public String getMimeType() {
return mimeType;
}
}
@@ -0,0 +1,79 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mozilla.components.browser.icons;

import java.util.Comparator;

/**
* This comparator implementation compares IconDescriptor objects in order to determine which icon
* to load first.
*
* In general this comparator will try touch icons before favicons (they usually have a higher resolution)
* and prefers larger icons over smaller ones.
*/
/* package-private */ class IconDescriptorComparator implements Comparator<IconDescriptor> {
@Override
public int compare(final IconDescriptor lhs, final IconDescriptor rhs) {
if (lhs.getUrl().equals(rhs.getUrl())) {
// Two descriptors pointing to the same URL are always referencing the same icon. So treat
// them as equal.
return 0;
}

// First compare the types. We prefer touch icons because they tend to have a higher resolution
// than ordinary favicons.
if (lhs.getType() != rhs.getType()) {
return compareType(lhs, rhs);
}

// If one of them is larger than pick the larger icon.
if (lhs.getSize() != rhs.getSize()) {
return compareSizes(lhs, rhs);
}

// If there's no other way to choose, we prefer container types. They *might* contain
// an image larger than the size given in the <link> tag.
final boolean lhsContainer = IconsHelper.isContainerType(lhs.getMimeType());
final boolean rhsContainer = IconsHelper.isContainerType(rhs.getMimeType());

if (lhsContainer != rhsContainer) {
return lhsContainer ? -1 : 1;
}

// There's no way to know which icon might be better. However we need to pick a consistent
// one to avoid breaking the TreeSet implementation (See Bug 1331808). Therefore we are
// picking one by just comparing the URLs.
return lhs.getUrl().compareTo(rhs.getUrl());
}

private int compareType(IconDescriptor lhs, IconDescriptor rhs) {
if (lhs.getType() > rhs.getType()) {
return -1;
} else {
return 1;
}
}

private int compareSizes(IconDescriptor lhs, IconDescriptor rhs) {
if (lhs.getSize() > rhs.getSize()) {
return -1;
} else {
return 1;
}
}
}

0 comments on commit c10f15b

Please sign in to comment.