summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/icons/IconRequest.java
blob: be000642ed8773c397fe6a9f1b3d858839365814 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/* -*- 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 org.mozilla.gecko.icons;

import android.content.Context;
import android.support.annotation.VisibleForTesting;

import org.mozilla.gecko.R;

import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.Future;

/**
 * A class describing a request to load an icon for a website.
 */
public class IconRequest {
    private Context context;

    // Those values are written by the IconRequestBuilder class.
    /* package-private */ String pageUrl;
    /* package-private */ boolean privileged;
    /* package-private */ TreeSet<IconDescriptor> icons;
    /* package-private */ boolean skipNetwork;
    /* package-private */ boolean backgroundThread;
    /* package-private */ boolean skipDisk;
    /* package-private */ boolean skipMemory;
    /* package-private */ int targetSize;
    /* package-private */ boolean prepareOnly;
    private IconCallback callback;

    /* package-private */ IconRequest(Context context) {
        this.context = context.getApplicationContext();
        this.icons = new TreeSet<>(new IconDescriptorComparator());

        // Setting some sensible defaults.
        this.privileged = false;
        this.skipMemory = false;
        this.skipDisk = false;
        this.skipNetwork = false;
        this.targetSize = context.getResources().getDimensionPixelSize(R.dimen.favicon_bg);
        this.prepareOnly = false;
    }

    /**
     * Execute this request and try to load an icon. Once an icon has been loaded successfully the
     * callback will be executed.
     *
     * The returned Future can be used to cancel the job.
     */
    public Future<IconResponse> execute(IconCallback callback) {
        setCallback(callback);

        return IconRequestExecutor.submit(this);
    }

    @VisibleForTesting void setCallback(IconCallback callback) {
        this.callback = callback;
    }

    /**
     * Get the (application) context associated with this request.
     */
    public Context getContext() {
        return context;
    }

    /**
     * Get the descriptor for the potentially best icon. This is the icon that should be loaded if
     * possible.
     */
    public IconDescriptor getBestIcon() {
        return icons.first();
    }

    /**
     * Get the URL of the page for which an icon should be loaded.
     */
    public String getPageUrl() {
        return pageUrl;
    }

    /**
     * Is this request allowed to load icons from internal data sources like the omni.ja?
     */
    public boolean isPrivileged() {
        return privileged;
    }

    /**
     * Get the number of icon descriptors associated with this request.
     */
    public int getIconCount() {
        return icons.size();
    }

    /**
     * Get the required target size of the icon.
     */
    public int getTargetSize() {
        return targetSize;
    }

    /**
     * Should a loader access the network to load this icon?
     */
    public boolean shouldSkipNetwork() {
        return skipNetwork;
    }

    /**
     * Should a loader access the disk to load this icon?
     */
    public boolean shouldSkipDisk() {
        return skipDisk;
    }

    /**
     * Should a loader access the memory cache to load this icon?
     */
    public boolean shouldSkipMemory() {
        return skipMemory;
    }

    /**
     * Get an iterator to iterate over all icon descriptors associated with this request.
     */
    public Iterator<IconDescriptor> getIconIterator() {
        return icons.iterator();
    }

    /**
     * Create a builder to modify this request.
     *
     * Calling methods on the builder will modify this object and not create a copy.
     */
    public IconRequestBuilder modify() {
        return new IconRequestBuilder(this);
    }

    /**
     * Should the callback be executed on a background thread? By default a callback is always
     * executed on the UI thread because an icon is usually loaded in order to display it somewhere
     * in the UI.
     */
    /* package-private */ boolean shouldRunOnBackgroundThread() {
        return backgroundThread;
    }

    /* package-private */ IconCallback getCallback() {
        return callback;
    }

    /* package-private */ boolean hasIconDescriptors() {
        return !icons.isEmpty();
    }

    /**
     * Move to the next icon. This method is called after all loaders for the current best icon
     * have failed. After calling this method getBestIcon() will return the next icon to try.
     * hasIconDescriptors() should be called before requesting the next icon.
     */
    /* package-private */ void moveToNextIcon() {
        if (!icons.remove(getBestIcon())) {
            // Calling this method when there's no next icon is an error (use hasIconDescriptors()).
            // Theoretically this method can fail even if there's a next icon (like it did in bug 1331808).
            // In this case crashing to see and fix the issue is desired.
            throw new IllegalStateException("Moving to next icon failed. Could not remove first icon from set.");
        }
    }

    /**
     * Should this request be prepared but not actually load an icon?
     */
    /* package-private */ boolean shouldPrepareOnly() {
        return prepareOnly;
    }
}