/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{
// This byte-code is generated from native/java/com/roli/juce/ComponentPeerView.java with min sdk version 16
// See juce_core/native/java/README.txt on how to generate this byte-code.
static const uint8 javaComponentPeerView[] =
{31,139,8,8,248,105,229,91,0,3,67,111,109,112,111,110,101,110,116,80,101,101,114,86,105,101,119,46,100,101,120,0,165,154,
11,124,92,85,157,199,255,231,220,59,51,201,100,50,153,76,210,164,73,38,233,228,217,105,155,38,83,160,208,146,180,244,13,
105,147,182,52,105,160,73,129,222,76,110,146,105,39,247,78,103,38,143,10,46,225,177,148,69,228,225,118,1,5,93,68,100,171,
162,219,34,178,5,92,101,149,197,174,162,91,124,176,85,235,10,10,31,145,45,136,221,186,174,136,178,191,115,238,153,100,
250,2,117,39,159,239,252,255,231,127,254,247,188,207,255,156,153,204,160,57,233,141,158,191,152,158,156,245,224,205,149,
149,85,69,59,14,196,31,217,241,202,99,15,124,242,195,239,188,245,102,211,239,146,201,249,68,73,34,154,236,189,32,72,234,
245,232,60,162,227,228,216,23,129,176,78,116,17,228,43,144,165,194,215,67,52,4,57,59,143,72,131,188,172,128,232,112,13,
209,126,200,19,229,68,39,193,59,160,116,54,81,57,168,2,53,160,14,52,130,121,96,21,88,11,58,64,23,216,2,118,130,7,193,211,
224,69,240,107,80,92,129,54,128,237,96,28,220,9,30,6,79,129,239,129,95,129,202,74,162,86,208,1,110,0,15,129,239,130,223,
129,198,42,162,30,240,0,248,15,240,54,168,9,17,45,7,6,184,22,220,1,30,3,71,193,27,32,80,77,212,0,86,131,43,192,45,224,33,
176,31,60,1,158,4,255,12,158,5,135,193,17,240,34,56,6,94,6,175,130,215,193,175,192,73,240,54,248,35,112,99,140,242,129,
31,148,130,10,80,13,234,64,19,152,15,150,131,110,112,13,216,5,38,192,77,224,78,240,0,120,24,28,4,79,131,23,193,15,193,
113,112,18,188,3,244,57,68,133,160,20,212,130,22,176,28,116,129,94,112,21,136,129,33,48,10,174,5,183,128,143,131,71,193,
19,224,107,224,8,248,49,120,11,252,30,248,194,24,103,80,15,154,193,82,176,1,244,131,36,184,30,220,9,62,15,190,8,158,4,95,
6,223,6,63,5,191,6,84,139,182,129,122,112,1,88,11,122,128,1,118,129,155,193,29,96,31,184,23,124,10,236,7,79,130,195,224,
135,224,21,112,2,188,13,220,117,152,43,80,5,26,192,50,208,9,186,193,0,24,1,73,48,9,174,5,55,128,219,192,93,224,30,240,25,
240,21,112,4,252,28,80,61,81,9,104,2,139,193,70,208,11,76,48,6,166,192,157,224,62,240,16,56,8,190,10,190,1,142,128,31,
129,151,193,27,224,36,248,45,168,106,192,88,129,21,96,45,216,10,98,224,58,112,59,248,24,120,28,124,11,188,6,126,3,244,70,
244,11,132,65,11,88,6,186,192,118,48,14,174,3,55,131,219,193,71,192,189,224,227,224,31,192,103,193,65,240,20,120,6,188,0,
142,129,55,193,219,224,15,128,154,80,7,200,107,114,246,175,11,96,75,147,31,20,129,0,40,6,34,32,148,144,179,231,103,129,
50,80,46,246,61,192,182,35,108,47,194,118,34,108,25,194,242,38,44,63,154,35,226,133,51,213,164,134,148,208,37,82,213,210,
92,16,1,8,49,132,208,67,11,64,51,88,8,90,64,43,136,170,184,115,30,56,31,92,0,22,131,37,224,82,208,5,54,130,77,96,51,57,
125,200,190,116,37,31,44,115,250,197,84,218,173,116,97,23,125,229,202,158,167,244,253,176,123,149,159,120,249,84,222,1,
101,247,43,187,87,141,75,86,159,149,227,47,198,229,80,153,163,139,49,121,70,61,91,171,124,10,212,88,136,54,20,170,241,56,
172,252,133,126,68,249,71,148,127,161,26,163,163,101,78,223,23,40,251,82,165,139,114,46,86,250,75,208,219,148,126,28,122,
187,210,79,66,95,166,116,29,147,183,92,233,1,232,151,40,61,4,125,133,210,27,160,175,202,206,75,142,253,130,28,189,29,250,
26,165,175,201,177,111,206,209,175,204,209,119,228,148,57,146,99,79,66,95,173,244,201,28,251,93,101,51,186,24,195,149,74,
159,202,41,231,214,28,127,49,110,107,179,207,194,190,78,233,247,229,248,236,207,209,15,148,59,235,168,89,141,231,101,74,
63,4,123,135,210,159,129,190,94,233,207,67,239,84,250,247,161,111,80,250,177,28,251,43,57,246,227,229,98,78,25,93,69,142,
60,70,98,223,132,233,74,37,239,148,146,209,71,148,220,167,228,223,41,121,143,146,247,42,255,7,73,236,181,102,250,123,41,
171,232,71,36,246,93,136,126,168,228,207,164,172,164,87,197,92,98,53,223,37,101,21,125,66,202,102,250,178,148,5,244,85,
185,254,106,233,66,18,123,166,132,14,146,216,35,213,244,117,18,235,222,77,163,82,6,232,3,144,249,200,103,82,46,164,231,
72,172,203,90,153,46,80,246,2,236,162,111,200,254,57,233,34,212,155,144,178,152,44,149,190,86,172,51,101,15,96,103,238,
86,233,49,41,53,26,39,39,214,76,40,57,41,37,163,41,37,111,32,177,215,56,165,164,172,163,235,73,196,163,26,89,95,9,162,
195,19,82,46,162,127,146,114,22,61,69,98,63,54,81,159,146,207,146,136,89,141,210,191,2,145,228,14,41,235,233,155,82,46,
166,239,203,241,156,43,243,43,81,194,151,228,56,206,147,233,42,216,47,87,114,139,148,62,234,150,178,132,126,160,228,139,
114,92,231,72,255,16,70,178,71,202,8,109,149,178,132,182,43,105,72,25,37,83,202,74,218,37,165,91,222,175,66,170,127,33,
68,191,180,148,249,180,71,74,47,93,167,242,63,40,101,30,253,149,148,206,56,132,208,179,155,148,188,89,201,191,150,114,54,
221,162,228,94,101,191,85,202,114,250,27,37,111,83,242,67,82,86,208,237,82,182,210,253,74,62,32,101,136,62,171,214,209,
231,148,124,84,201,207,171,252,47,168,244,63,42,121,64,173,179,199,164,12,211,23,165,108,164,199,165,116,230,43,164,230,
75,164,15,169,245,249,164,148,206,252,133,16,237,159,150,114,1,29,86,242,223,164,108,160,231,165,44,165,239,72,57,159,
254,93,165,143,40,191,23,148,252,174,202,255,158,234,255,207,73,196,224,32,101,164,188,144,62,38,247,129,159,94,38,17,
119,157,245,219,132,104,107,147,136,189,26,13,72,201,233,83,36,226,111,17,125,148,156,179,142,200,137,211,34,62,137,51,
99,7,228,87,84,176,174,82,107,184,73,249,137,252,36,242,95,80,249,226,60,40,38,231,60,189,79,61,63,5,249,187,200,140,255,
109,208,239,142,56,231,217,253,144,15,129,71,35,206,185,245,37,105,231,206,222,107,18,251,18,119,175,96,1,37,3,6,108,65,
218,30,240,202,51,42,15,41,241,124,41,124,250,69,125,238,82,170,227,62,248,229,227,233,158,116,1,245,156,239,35,43,112,
62,188,124,44,72,75,89,251,140,53,124,17,118,199,140,207,34,248,120,181,45,56,178,182,52,50,58,216,115,55,105,250,226,29,
149,180,53,237,165,37,90,25,5,181,237,208,178,254,61,153,2,218,29,104,194,62,247,233,187,3,243,33,11,244,221,209,5,180,
218,37,252,151,106,30,186,104,135,139,130,37,226,25,63,234,42,195,92,88,129,89,104,239,233,117,68,190,35,206,113,77,142,
201,210,38,231,78,210,31,244,169,190,214,97,46,146,225,90,140,118,127,192,79,253,37,133,178,223,76,254,33,126,55,57,119,
128,100,64,220,52,252,211,246,203,167,237,17,105,231,234,102,176,77,221,129,122,2,133,114,126,52,216,69,189,70,147,115,
46,247,132,11,209,74,113,3,65,15,107,69,187,171,80,179,127,218,111,228,156,126,33,233,231,71,92,16,61,177,225,39,214,127,
208,29,156,149,12,151,211,103,168,78,23,179,231,65,171,250,247,33,186,233,85,148,140,214,211,190,252,254,125,1,10,233,46,
148,112,13,61,76,94,125,137,126,21,205,241,138,52,195,202,237,123,160,8,90,63,197,105,251,253,136,180,225,30,218,134,247,
173,242,189,23,43,181,14,43,35,25,16,61,45,209,75,169,126,229,66,106,98,34,142,89,97,23,218,211,35,106,114,121,49,126,
110,18,37,230,33,102,5,53,43,48,128,167,124,122,165,235,91,20,108,170,31,106,165,160,103,32,175,132,186,242,220,158,96,
121,40,175,64,106,86,244,106,234,113,251,180,37,90,41,5,121,176,161,126,77,148,130,174,221,129,29,232,157,207,221,229,
214,93,193,89,65,41,173,168,73,127,171,99,12,2,28,81,204,167,207,209,157,214,239,163,200,39,11,245,200,73,112,2,188,5,
126,4,142,98,202,229,29,115,230,53,117,9,253,89,233,211,95,78,190,56,191,203,16,143,76,114,206,19,174,213,223,204,234,
110,100,243,166,24,159,123,43,107,188,133,57,243,45,94,63,80,235,160,59,92,36,247,177,88,127,34,125,44,187,110,162,203,
168,86,19,179,233,236,175,87,213,186,236,94,81,68,101,92,222,87,249,82,228,248,165,37,25,189,152,116,22,121,123,166,252,
55,154,156,251,168,184,67,247,161,14,191,170,67,188,254,187,201,217,255,193,64,209,244,186,252,131,106,207,214,64,177,
172,135,171,117,204,231,58,119,68,43,176,88,236,28,220,5,117,249,92,144,34,127,212,84,121,121,115,157,152,225,151,207,57,
55,221,64,142,205,13,155,240,44,159,251,222,125,88,162,250,144,245,15,191,143,255,210,233,62,59,237,152,119,150,118,44,
58,139,109,73,142,77,87,117,93,50,215,185,55,7,153,136,188,253,81,78,142,212,104,219,34,68,145,183,182,69,61,180,45,234,
86,214,124,172,31,220,220,3,219,162,58,242,243,176,11,202,208,158,106,10,179,98,213,95,49,246,27,231,58,49,248,236,237,
239,89,21,164,228,150,149,164,95,30,249,95,241,25,65,147,243,222,123,206,103,206,95,251,238,187,178,223,43,90,73,55,196,
51,249,176,139,122,98,115,157,251,122,176,184,123,0,79,233,226,41,174,203,153,194,248,53,123,196,103,36,145,99,5,124,136,
215,216,141,155,219,168,41,205,2,145,19,118,116,54,141,231,121,41,242,134,21,136,162,221,62,220,46,52,248,137,81,66,190,
184,232,113,167,93,217,207,96,37,106,220,4,94,228,136,250,175,159,235,124,158,10,178,233,250,57,234,199,147,69,108,169,
39,31,229,121,209,86,47,15,214,159,119,158,135,236,21,21,52,126,159,151,69,78,88,129,2,17,7,248,18,254,198,187,89,221,10,
199,208,106,175,108,175,108,167,22,44,142,252,196,25,31,81,215,71,231,58,159,129,78,29,31,167,167,194,38,250,232,70,93,
201,45,237,24,217,96,32,242,27,231,174,41,94,143,228,204,123,62,74,19,229,61,174,198,219,190,178,146,122,198,115,75,93,
130,58,157,117,118,21,214,153,243,89,149,203,207,104,255,138,103,66,40,168,251,5,120,99,241,44,98,76,91,202,208,6,86,196,
172,128,56,31,188,249,86,64,196,226,2,207,15,238,126,151,22,176,255,145,163,19,249,117,247,119,177,115,152,21,14,224,86,
233,213,45,236,53,248,186,172,64,80,72,183,231,133,241,188,229,226,116,45,142,28,123,127,207,21,142,231,55,222,223,243,
18,120,90,1,17,3,188,5,193,226,139,170,230,83,176,182,62,212,130,24,121,30,125,155,130,149,139,159,170,37,81,138,40,227,
11,162,140,112,137,144,44,232,90,227,242,185,110,220,250,220,44,43,92,234,88,202,214,184,125,238,27,135,158,43,203,150,
123,212,139,153,124,9,237,184,169,148,209,187,184,55,220,253,178,151,229,45,245,206,166,63,181,7,243,104,232,221,220,246,
252,37,45,17,37,69,126,252,231,183,96,185,106,65,227,255,187,5,203,101,11,196,182,241,200,181,38,214,150,136,21,173,74,
138,24,35,238,165,105,185,246,184,60,163,47,142,56,223,65,160,141,56,17,61,88,253,149,26,230,163,180,126,13,78,68,215,
128,27,39,162,60,221,174,166,243,116,31,91,138,146,253,184,53,70,254,8,222,9,6,235,235,112,30,106,226,60,204,195,153,215,
165,115,77,156,131,187,121,228,205,66,30,57,14,94,7,175,137,245,94,140,182,137,251,162,216,25,156,207,45,107,156,173,213,
71,234,154,231,205,207,137,137,131,145,153,189,161,41,107,34,226,220,251,150,112,15,246,151,21,222,6,15,63,5,87,68,126,
47,250,231,196,205,177,136,243,157,137,136,31,226,134,87,201,239,131,167,134,88,42,98,73,5,226,210,108,228,13,98,135,122,
217,50,86,130,209,182,162,97,138,162,199,23,74,127,43,58,135,2,122,207,162,0,238,114,13,178,252,108,78,144,91,209,26,10,
112,39,79,124,170,138,156,112,190,243,205,125,61,126,90,250,217,211,210,162,79,165,228,156,119,197,104,5,83,54,231,51,
148,35,243,148,44,87,178,74,249,55,225,51,148,72,71,84,58,130,217,212,41,123,247,83,231,163,154,235,236,57,202,213,92,
103,207,79,71,247,200,239,98,184,164,57,199,46,100,161,76,235,170,110,183,202,115,195,143,43,155,71,201,124,37,125,234,
89,63,90,228,204,175,58,207,213,51,33,53,127,226,51,147,200,111,86,109,108,206,105,183,96,161,146,45,234,121,166,238,26,
66,22,77,219,138,84,93,206,115,129,233,186,152,250,28,131,182,182,199,173,120,102,57,149,173,182,71,147,182,101,90,153,
205,166,153,234,141,155,19,45,59,141,113,220,161,215,17,95,215,65,172,131,120,7,196,122,226,235,59,169,124,131,185,103,
192,54,82,131,107,226,233,209,120,58,221,25,79,103,76,203,76,17,235,36,222,9,215,206,78,210,58,241,86,214,105,88,131,41,
59,62,216,106,36,147,173,43,99,153,248,120,60,179,167,141,46,56,213,158,76,38,226,49,35,19,183,173,134,172,79,103,124,
200,140,237,137,37,204,213,70,34,49,96,196,118,165,219,168,226,92,79,229,102,197,108,11,109,201,180,174,22,114,50,147,
155,53,156,50,146,35,241,88,186,117,181,97,141,27,40,176,230,44,89,118,194,78,173,139,39,50,102,234,220,249,93,70,38,21,
159,108,163,121,239,153,127,74,81,179,207,116,221,108,196,45,180,175,252,204,156,45,102,12,25,37,211,25,118,186,117,213,
152,53,152,48,219,168,52,215,216,177,42,110,13,138,210,103,202,24,199,204,181,98,122,214,142,155,162,240,202,83,51,186,
108,49,92,42,111,222,169,121,98,206,27,54,89,235,236,216,88,122,245,136,97,13,155,217,105,205,109,202,180,107,110,151,
166,141,151,166,236,177,100,27,93,120,102,78,79,202,52,55,13,164,205,212,184,153,66,45,151,38,236,1,35,209,105,236,177,
199,50,51,213,204,121,239,231,218,168,229,84,135,184,149,28,203,140,154,153,17,123,176,117,149,145,54,59,68,26,19,111,97,
252,228,178,104,60,183,255,218,193,120,198,78,117,88,67,118,27,205,63,183,219,25,69,46,124,31,223,46,169,119,25,150,49,
44,90,188,174,51,102,143,182,166,236,68,188,117,231,88,204,108,61,99,155,53,156,99,47,53,156,218,243,165,127,105,57,109,
84,251,126,143,182,81,93,231,160,145,24,143,239,106,53,44,203,206,200,61,213,186,214,138,37,236,116,220,26,94,157,48,210,
114,179,156,233,211,129,113,73,169,252,218,179,228,119,153,163,3,202,193,76,139,21,35,98,74,107,2,139,171,21,75,44,213,
109,238,30,51,173,24,150,117,113,110,142,83,94,93,142,169,35,145,48,135,141,196,202,88,204,76,167,215,78,198,204,164,51,
25,13,103,241,73,13,143,141,162,115,57,94,37,185,94,136,10,195,206,168,204,24,55,218,221,99,177,17,103,230,114,158,11,
230,184,108,26,216,41,55,101,117,142,173,219,140,141,165,16,171,206,241,72,55,130,128,53,44,86,204,140,45,101,14,37,80,
14,154,49,110,59,177,171,199,72,13,155,185,173,173,60,139,187,211,180,54,210,123,182,109,94,75,190,220,165,65,172,151,
120,111,7,185,122,59,240,130,186,158,220,189,235,59,214,173,91,79,58,100,135,120,23,225,184,119,125,31,50,133,210,185,94,
188,73,173,15,185,157,125,8,234,189,125,120,170,79,150,192,250,72,235,19,207,225,173,83,168,136,233,125,66,17,129,189,31,
199,65,127,7,5,251,207,156,175,146,254,179,12,151,215,144,83,214,16,141,70,167,245,69,57,250,121,57,250,249,57,250,5,208,
11,28,125,93,194,24,78,147,219,144,251,79,24,133,236,52,6,204,4,229,25,234,180,160,10,99,112,240,236,81,133,216,0,21,139,
3,100,213,88,38,99,91,155,83,40,210,28,36,247,128,141,228,40,164,12,172,228,142,201,51,129,60,49,25,250,6,201,133,179,
199,72,81,65,204,30,52,55,219,136,212,43,51,34,49,29,221,201,47,19,61,41,195,74,15,217,169,81,42,20,39,15,66,122,90,122,
163,32,231,0,66,65,246,24,210,250,96,124,104,136,152,73,46,83,132,95,242,13,205,4,218,65,202,199,26,88,233,244,112,150,
80,103,206,54,117,142,81,33,204,98,207,160,203,102,42,77,121,34,41,6,158,188,66,83,78,62,177,148,68,241,61,241,81,83,22,
122,153,25,31,30,201,80,9,212,78,181,226,54,89,221,49,44,32,75,230,59,43,139,138,160,202,118,99,183,202,230,250,102,12,
29,131,228,65,106,139,49,113,101,86,217,70,5,66,177,237,140,136,31,20,64,162,123,15,198,123,180,27,107,50,30,51,201,15,
203,86,43,46,6,79,52,90,214,127,122,56,151,93,234,141,167,227,3,241,132,152,67,241,204,21,56,208,236,137,30,123,23,154,
23,154,78,75,167,132,137,200,150,76,24,123,214,165,12,116,78,71,238,149,242,29,87,219,17,42,194,64,98,30,49,112,155,141,
49,49,193,129,105,195,22,51,141,136,48,109,89,53,189,22,168,208,177,32,114,174,177,39,176,182,166,147,91,147,84,58,157,
144,81,245,178,248,224,32,218,164,170,233,178,81,135,124,230,20,67,202,24,206,150,41,13,40,70,149,41,207,122,202,27,49,
210,242,124,165,242,145,248,160,217,109,15,101,228,153,177,46,101,143,58,61,133,11,28,123,196,92,234,35,118,58,67,44,78,
94,204,229,38,25,28,210,164,197,71,71,169,72,92,217,226,70,98,181,145,76,119,97,132,169,80,25,186,205,196,90,107,112,58,
31,201,238,140,145,202,80,190,60,165,122,246,36,77,242,73,245,26,231,196,34,119,28,113,104,151,137,42,210,29,86,58,99,32,
22,83,94,60,189,41,105,32,48,227,177,180,26,121,242,236,50,247,172,22,85,149,239,58,199,213,175,48,155,209,61,34,198,197,
149,144,59,180,16,243,101,166,68,205,27,113,228,144,158,48,135,50,228,78,152,214,112,102,132,220,170,21,204,34,221,18,
115,234,177,204,137,141,114,114,237,196,224,136,124,159,160,98,219,202,94,10,87,167,76,35,131,153,44,153,49,173,49,211,
153,148,189,71,76,239,140,81,45,129,156,39,179,107,160,106,198,212,109,140,155,217,78,99,152,50,102,174,191,28,183,83,
139,232,206,216,201,36,76,133,182,37,150,80,54,144,148,99,139,202,102,157,118,83,32,183,109,97,65,76,8,255,156,59,21,249,
237,83,194,20,229,219,86,118,253,21,74,181,107,44,145,137,39,197,152,203,36,214,80,158,136,119,210,25,30,221,241,15,152,
217,168,225,195,241,97,227,228,146,91,30,21,58,211,230,113,228,53,120,110,12,81,43,131,104,225,74,202,245,231,77,26,41,
120,202,61,235,74,202,48,197,82,84,151,50,135,197,44,166,206,125,247,166,80,202,28,181,199,77,167,229,155,172,211,66,172,
43,37,131,140,150,54,51,228,79,139,112,52,125,243,37,31,210,178,255,134,88,71,229,185,169,14,167,245,114,9,139,199,114,
238,79,242,177,206,236,218,161,217,72,157,245,106,74,179,210,217,208,179,53,158,19,75,170,206,106,22,55,31,3,97,60,237,4,
35,185,212,10,211,167,4,33,111,54,153,112,218,116,69,60,145,216,104,103,228,76,250,210,88,218,217,128,128,7,145,154,222,
194,112,22,75,198,105,23,142,125,100,99,189,204,36,103,167,157,214,116,204,212,165,122,170,103,70,226,56,223,196,123,67,
84,201,69,176,138,8,174,161,12,168,98,8,242,198,50,67,75,100,44,101,227,228,26,55,18,98,166,165,216,52,68,186,184,139,82,
145,120,207,93,31,249,194,208,99,111,77,155,20,24,63,61,250,122,199,103,122,205,38,136,77,18,159,140,130,69,196,246,208,
65,206,200,227,239,107,167,67,248,0,220,220,175,241,175,179,194,189,26,251,23,86,50,71,163,56,111,153,252,237,206,118,86,
92,28,111,231,233,234,118,122,144,115,122,149,121,252,252,226,109,252,210,137,133,244,113,206,94,71,242,12,249,8,10,243,
63,78,159,115,68,141,54,252,21,118,55,243,52,243,23,168,141,191,201,38,248,215,63,56,113,43,227,46,239,202,133,237,45,
237,237,203,251,53,26,244,94,167,49,179,165,253,145,90,77,251,52,91,192,202,103,69,107,52,254,16,227,172,184,220,197,249,
229,213,46,114,49,151,230,246,242,5,15,187,188,110,114,51,55,119,107,243,231,243,241,102,23,159,207,211,205,84,225,84,93,
193,95,103,255,37,148,151,68,199,110,11,17,206,50,255,6,122,66,227,191,100,199,133,125,39,210,244,168,38,222,143,105,188,
239,26,200,23,53,214,7,241,140,20,120,228,23,82,249,80,136,142,40,135,159,57,14,223,116,196,207,57,251,42,243,84,111,216,
176,176,111,67,95,11,25,108,135,124,234,70,141,191,196,238,64,21,31,170,90,72,191,100,252,19,108,151,167,122,47,15,86,
243,100,53,47,106,251,52,207,84,111,255,52,159,172,166,219,185,246,9,54,130,76,94,120,11,31,175,190,167,127,231,94,141,
126,202,120,31,221,200,229,83,254,189,225,208,61,244,123,238,50,62,197,126,194,158,99,87,163,210,19,92,127,141,221,196,
62,203,62,131,26,150,237,237,163,61,210,145,31,166,106,254,212,245,213,27,180,252,43,121,167,230,57,198,48,133,180,141,
175,104,102,37,69,81,135,64,167,86,240,8,227,203,218,53,223,215,88,235,50,198,52,239,71,24,95,200,66,133,151,184,188,46,
223,34,87,193,78,183,183,133,149,148,241,107,219,218,221,190,101,172,122,150,176,159,106,228,235,88,181,159,238,214,216,
47,80,127,88,99,71,49,73,193,50,238,107,230,163,213,88,42,59,35,53,46,18,178,169,222,69,47,71,231,211,135,53,182,95,12,
247,65,141,109,247,248,227,33,250,54,99,255,9,195,179,26,237,99,149,45,59,55,76,238,168,216,75,188,154,189,196,102,87,
241,26,222,171,243,71,88,249,69,142,33,36,13,65,24,242,249,28,24,66,108,118,101,86,169,34,206,152,151,179,187,194,181,83,
83,250,243,229,117,236,173,114,210,220,228,187,43,140,213,194,235,111,152,210,15,85,176,91,195,175,137,183,169,74,188,
221,87,201,248,1,112,180,146,244,162,138,34,206,228,223,60,56,78,85,33,251,193,26,188,29,170,209,111,228,148,15,216,159,
64,8,52,179,35,53,140,77,205,97,236,129,57,165,236,0,228,97,112,28,76,133,25,219,7,158,5,39,193,173,181,240,1,7,192,205,
117,140,29,2,199,5,245,140,29,109,96,250,190,70,166,239,111,100,236,88,163,206,30,158,15,191,5,156,61,11,94,91,160,190,
203,201,126,71,150,149,217,223,97,138,239,120,178,191,197,20,223,9,101,127,143,169,211,204,111,50,197,119,74,217,223,101,
102,191,183,18,191,205,212,2,142,46,190,171,99,97,231,55,72,207,67,119,135,29,187,248,63,54,11,56,223,171,201,255,109,
135,157,122,197,111,57,53,229,47,254,231,172,135,157,114,197,255,169,73,61,43,255,255,29,112,218,42,126,55,250,127,111,
26,247,20,112,42,0,0};

//==============================================================================
#if JUCE_PUSH_NOTIFICATIONS && JUCE_MODULE_AVAILABLE_juce_gui_extra
 // Returns true if the intent was handled.
 extern bool juce_handleNotificationIntent (void*);
 extern void juce_firebaseDeviceNotificationsTokenRefreshed (void*);
 extern void juce_firebaseRemoteNotificationReceived (void*);
 extern void juce_firebaseRemoteMessagesDeleted();
 extern void juce_firebaseRemoteMessageSent(void*);
 extern void juce_firebaseRemoteMessageSendError (void*, void*);
#endif

#if JUCE_IN_APP_PURCHASES && JUCE_MODULE_AVAILABLE_juce_product_unlocking
 extern void juce_inAppPurchaseCompleted (void*);
#endif

extern void juce_contentSharingCompleted (int);

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (create,                      "<init>",                      "(II)V")

DECLARE_JNI_CLASS (AndroidLayoutParams, "android/view/ViewGroup$LayoutParams")
#undef JNI_CLASS_MEMBERS

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (addView,       "addView",             "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") \
 METHOD (removeView, "removeView", "(Landroid/view/View;)V") \
 METHOD (updateViewLayout, "updateViewLayout", "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V")

DECLARE_JNI_CLASS (AndroidViewManager, "android/view/ViewManager")
#undef JNI_CLASS_MEMBERS

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (create,           "<init>",             "(IIIIIII)V") \
 FIELD  (gravity,          "gravity",            "I") \
 FIELD  (windowAnimations, "windowAnimations",   "I")

DECLARE_JNI_CLASS (AndroidWindowManagerLayoutParams, "android/view/WindowManager$LayoutParams")
#undef JNI_CLASS_MEMBERS

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getDecorView, "getDecorView",       "()Landroid/view/View;") \
 METHOD (setFlags,     "setFlags",           "(II)V")

DECLARE_JNI_CLASS (AndroidWindow, "android/view/Window")
#undef JNI_CLASS_MEMBERS


//==============================================================================
class AndroidComponentPeer  : public ComponentPeer,
                              private Timer
{
public:
    AndroidComponentPeer (Component& comp, const int windowStyleFlags, void* nativeViewHandle)
        : ComponentPeer (comp, windowStyleFlags),
          fullScreen (false),
          navBarsHidden (false),
          sizeAllocated (0),
          scale ((float) Desktop::getInstance().getDisplays().getMainDisplay().scale)
    {
        auto* env = getEnv();

        // NB: must not put this in the initialiser list, as it invokes a callback,
        // which will fail if the peer is only half-constructed.
        view = GlobalRef (LocalRef<jobject> (env->NewObject (ComponentPeerView, ComponentPeerView.create,
                                                             getAppContext().get(), (jboolean) component.isOpaque(),
                                                             (jlong) this)));

        if (nativeViewHandle != nullptr)
        {
            viewGroupIsWindow = false;

            // we don't know if the user is holding on to a local ref to this, so
            // explicitly create a new one
            auto nativeView = LocalRef<jobject>(env->NewLocalRef(static_cast<jobject> (nativeViewHandle)));

            if (env->IsInstanceOf (nativeView.get(), AndroidActivity))
            {
                viewGroup = GlobalRef (nativeView);
                env->CallVoidMethod (viewGroup.get(), AndroidActivity.setContentView, view.get());
            }
            else if (env->IsInstanceOf (nativeView.get(), AndroidViewGroup))
            {
                viewGroup = GlobalRef (nativeView);
                LocalRef<jobject> layoutParams (env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2));

                env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, layoutParams.get());
                env->CallVoidMethod ((jobject) viewGroup.get(), AndroidViewGroup.addView, view.get());
            }
            else
            {
                // the native handle you passed as a second argument to Component::addToDesktop must
                // either be an Activity or a ViewGroup
                jassertfalse;
            }
        }
        else
        {
            viewGroupIsWindow = true;

            LocalRef<jobject> viewLayoutParams (env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2));

            env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, viewLayoutParams.get());

            Rectangle<int> physicalBounds = comp.getBoundsInParent() * scale;

            view.callVoidMethod (AndroidView.layout,
                                 physicalBounds.getX(), physicalBounds.getY(), physicalBounds.getRight(), physicalBounds.getBottom());

            LocalRef<jobject> windowLayoutParams (env->NewObject (AndroidWindowManagerLayoutParams, AndroidWindowManagerLayoutParams.create,
                                                                  physicalBounds.getWidth(), physicalBounds.getHeight(),
                                                                  physicalBounds.getX(), physicalBounds.getY(),
                                                                  TYPE_APPLICATION, FLAG_NOT_TOUCH_MODAL | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_NO_LIMITS,
                                                                  component.isOpaque() ? PIXEL_FORMAT_OPAQUE : PIXEL_FORMAT_TRANSPARENT));
            env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.gravity, GRAVITY_LEFT | GRAVITY_TOP);
            env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.windowAnimations, 0x01030000 /* android.R.style.Animation */);
            viewGroup = GlobalRef (LocalRef<jobject> (env->CallObjectMethod (getCurrentActivity().get(), AndroidContext.getSystemService, javaString ("window").get())));

            env->CallVoidMethod (viewGroup.get(), AndroidViewManager.addView, view.get(), windowLayoutParams.get());
        }

        if (isFocused())
            handleFocusGain();
    }

    ~AndroidComponentPeer()
    {
        auto* env = getEnv();

        env->CallVoidMethod (view, ComponentPeerView.clear);
        frontWindow = nullptr;

        if (MessageManager::getInstance()->isThisTheMessageThread())
        {
            if (env->IsInstanceOf (viewGroup.get(), AndroidActivity))
                env->CallVoidMethod (viewGroup.get(), AndroidActivity.setContentView, nullptr);
            else
                env->CallVoidMethod (viewGroup.get(), AndroidViewManager.removeView, view.get());
        }
        else
        {
            struct ViewDeleter  : public CallbackMessage
            {
                ViewDeleter (const GlobalRef& view_, const GlobalRef& viewGroup_) : view (view_), group (viewGroup_) {}

                void messageCallback() override
                {
                    auto* callbackEnv = getEnv();

                    if (callbackEnv->IsInstanceOf (group.get(), AndroidActivity))
                        callbackEnv->CallVoidMethod (group.get(), AndroidActivity.setContentView, nullptr);
                    else
                        callbackEnv->CallVoidMethod (group.get(), AndroidViewManager.removeView, view.get());
                }

            private:
                GlobalRef view, group;
            };

            (new ViewDeleter (view, viewGroup))->post();
        }
    }

    void* getNativeHandle() const override
    {
        return (void*) view.get();
    }

    void setVisible (bool shouldBeVisible) override
    {
        if (MessageManager::getInstance()->isThisTheMessageThread())
        {
            view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible);
        }
        else
        {
            struct VisibilityChanger  : public CallbackMessage
            {
                VisibilityChanger (const GlobalRef& view_, bool shouldBeVisible_)
                    : view (view_), shouldBeVisible (shouldBeVisible_)
                {}

                void messageCallback() override
                {
                    view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible);
                }

                GlobalRef view;
                bool shouldBeVisible;
            };

            (new VisibilityChanger (view, shouldBeVisible))->post();
        }
    }

    void setTitle (const String& title) override
    {
        view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get());
    }

    void setBounds (const Rectangle<int>& userRect, bool isNowFullScreen) override
    {
        Rectangle<int> r = (userRect.toFloat() * scale).toNearestInt();

        if (MessageManager::getInstance()->isThisTheMessageThread())
        {
            auto* env = getEnv();

            fullScreen = isNowFullScreen;

            {
                view.callVoidMethod (AndroidView.layout,
                                     r.getX(), r.getY(), r.getRight(), r.getBottom());

                if (viewGroup != nullptr && viewGroupIsWindow)
                {
                    LocalRef<jobject> windowLayoutParams (env->NewObject (AndroidWindowManagerLayoutParams, AndroidWindowManagerLayoutParams.create,
                                                                          r.getWidth(), r.getHeight(),
                                                                          r.getX(), r.getY(),
                                                                          TYPE_APPLICATION, FLAG_NOT_TOUCH_MODAL | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_NO_LIMITS,
                                                                          component.isOpaque() ? PIXEL_FORMAT_OPAQUE : PIXEL_FORMAT_TRANSPARENT));
                    env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.gravity, 0x3 /* LEFT */ | 0x30 /* TOP */);
                    env->CallVoidMethod (viewGroup.get(), AndroidViewManager.updateViewLayout, view.get(), windowLayoutParams.get());
                }
            }
        }
        else
        {
            class ViewMover  : public CallbackMessage
            {
            public:
                ViewMover (const GlobalRef& v, const Rectangle<int>& boundsToUse)  : view (v), bounds (boundsToUse) {}

                void messageCallback() override
                {
                    view.callVoidMethod (AndroidView.layout,
                                         bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getBottom());
                }

            private:
                GlobalRef view;
                Rectangle<int> bounds;
            };

            (new ViewMover (view, r))->post();
        }
    }

    Rectangle<int> getBounds() const override
    {
        Rectangle<int> r (view.callIntMethod (AndroidView.getLeft),
                          view.callIntMethod (AndroidView.getTop),
                          view.callIntMethod (AndroidView.getWidth),
                          view.callIntMethod (AndroidView.getHeight));

        return r / scale;
    }

    void handleScreenSizeChange() override
    {
        ComponentPeer::handleScreenSizeChange();

        if (isFullScreen())
            setFullScreen (true);
    }

    Point<int> getScreenPosition() const
    {
        auto* env = getEnv();

        LocalRef<jintArray> position (env->NewIntArray (2));
        env->CallVoidMethod (view.get(), AndroidView.getLocationOnScreen, position.get());

        jint* const screenPosition = env->GetIntArrayElements (position.get(), 0);
        Point<int> pos (screenPosition[0], screenPosition[1]);
        env->ReleaseIntArrayElements (position.get(), screenPosition, 0);

        return pos;
    }

    Point<float> localToGlobal (Point<float> relativePosition) override
    {
        return relativePosition + (getScreenPosition().toFloat() / scale);
    }

    Point<float> globalToLocal (Point<float> screenPosition) override
    {
        return screenPosition - (getScreenPosition().toFloat() / scale);
    }

    void setMinimised (bool /*shouldBeMinimised*/) override
    {
        // n/a
    }

    bool isMinimised() const override
    {
        return false;
    }

    bool shouldNavBarsBeHidden (bool shouldBeFullScreen) const
    {
        if (shouldBeFullScreen)
            if (Component* kiosk = Desktop::getInstance().getKioskModeComponent())
                if (kiosk->getPeer() == this)
                    return true;

        return false;
    }

    void setNavBarsHidden (bool hidden)
    {
        enum
        {
            SYSTEM_UI_FLAG_VISIBLE                  = 0,
            SYSTEM_UI_FLAG_LOW_PROFILE              = 1,
            SYSTEM_UI_FLAG_HIDE_NAVIGATION          = 2,
            SYSTEM_UI_FLAG_FULLSCREEN               = 4,
            SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION   = 512,
            SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN        = 1024,
            SYSTEM_UI_FLAG_IMMERSIVE                = 2048,
            SYSTEM_UI_FLAG_IMMERSIVE_STICKY         = 4096
        };

        view.callVoidMethod (ComponentPeerView.setSystemUiVisibilityCompat,
                             hidden ? (jint) (SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
                                    : (jint) (SYSTEM_UI_FLAG_VISIBLE));

        navBarsHidden = hidden;
    }

    void setFullScreen (bool shouldBeFullScreen) override
    {
        // updating the nav bar visibility is a bit odd on Android - need to wait for
        if (shouldNavBarsBeHidden (shouldBeFullScreen))
        {
            if (! navBarsHidden && ! isTimerRunning())
            {
                startTimer (500);
            }
        }
        else
        {
            setNavBarsHidden (false);
        }

        Rectangle<int> r (shouldBeFullScreen ? Desktop::getInstance().getDisplays().getMainDisplay().userArea
                                             : lastNonFullscreenBounds);

        if ((! shouldBeFullScreen) && r.isEmpty())
            r = getBounds();

        // (can't call the component's setBounds method because that'll reset our fullscreen flag)
        if (! r.isEmpty())
            setBounds (r, shouldBeFullScreen);

        component.repaint();
    }

    bool isFullScreen() const override
    {
        return fullScreen;
    }

    void timerCallback() override
    {
        setNavBarsHidden (shouldNavBarsBeHidden (fullScreen));
        setFullScreen (fullScreen);
        stopTimer();
    }

    void setIcon (const Image& /*newIcon*/) override
    {
        // n/a
    }

    bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
    {
        return isPositiveAndBelow (localPos.x, component.getWidth())
            && isPositiveAndBelow (localPos.y, component.getHeight())
            && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint,
                                                                    localPos.x * scale,
                                                                    localPos.y * scale));
    }

    BorderSize<int> getFrameSize() const override
    {
        // TODO
        return BorderSize<int>();
    }

    bool setAlwaysOnTop (bool /*alwaysOnTop*/) override
    {
        // TODO
        return false;
    }

    void toFront (bool makeActive) override
    {
        // Avoid calling bringToFront excessively: it's very slow
        if (frontWindow != this)
        {
            view.callVoidMethod (AndroidView.bringToFront);

            frontWindow = this;
        }

        if (makeActive)
            grabFocus();

        handleBroughtToFront();
    }

    void toBehind (ComponentPeer*) override
    {
        // TODO
    }

    //==============================================================================
    void handleMouseDownCallback (int index, Point<float> sysPos, int64 time)
    {
        lastMousePos = sysPos / scale;
        Point<float> pos = globalToLocal (lastMousePos);

        // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
        handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, ModifierKeys::currentModifiers.withoutMouseButtons(),
                          MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index);

        if (isValidPeer (this))
            handleMouseDragCallback (index, sysPos, time);
    }

    void handleMouseDragCallback (int index, Point<float> sysPos, int64 time)
    {
        lastMousePos = sysPos / scale;
        Point<float> pos = globalToLocal (lastMousePos);

        jassert (index < 64);
        touchesDown = (touchesDown | (1 << (index & 63)));
        ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
        handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier),
                          MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index);
    }

    void handleMouseUpCallback (int index, Point<float> sysPos, int64 time)
    {
        lastMousePos = sysPos / scale;
        Point<float> pos = globalToLocal (lastMousePos);

        jassert (index < 64);
        touchesDown = (touchesDown & ~(1 << (index & 63)));

        if (touchesDown == 0)
            ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons();

        handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, ModifierKeys::currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure,
                          MouseInputSource::invalidOrientation, time, {}, index);
    }

    void handleKeyDownCallback (int k, int kc)
    {
        handleKeyPress (k, static_cast<juce_wchar> (kc));
    }

    void handleKeyUpCallback (int /*k*/, int /*kc*/)
    {
    }

    void handleBackButtonCallback()
    {
        if (auto* app = JUCEApplicationBase::getInstance())
            app->backButtonPressed();

        if (Component* kiosk = Desktop::getInstance().getKioskModeComponent())
            if (kiosk->getPeer() == this)
                setNavBarsHidden (navBarsHidden);
    }

    void handleKeyboardHiddenCallback()
    {
        Component::unfocusAllComponents();
    }

    void handleAppPausedCallback() {}

    void handleAppResumedCallback()
    {
        if (Component* kiosk = Desktop::getInstance().getKioskModeComponent())
            if (kiosk->getPeer() == this)
                setNavBarsHidden (navBarsHidden);
    }

    //==============================================================================
    bool isFocused() const override
    {
        if (view != nullptr)
            return view.callBooleanMethod (AndroidView.hasFocus);

        return false;
    }

    void grabFocus() override
    {
        if (view != nullptr)
            view.callBooleanMethod (AndroidView.requestFocus);
    }

    void handleFocusChangeCallback (bool hasFocus)
    {
        if (hasFocus)
            handleFocusGain();
        else
            handleFocusLoss();
    }

    static const char* getVirtualKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
    {
        switch (type)
        {
            case TextInputTarget::textKeyboard:          return "text";
            case TextInputTarget::numericKeyboard:       return "number";
            case TextInputTarget::decimalKeyboard:       return "numberDecimal";
            case TextInputTarget::urlKeyboard:           return "textUri";
            case TextInputTarget::emailAddressKeyboard:  return "textEmailAddress";
            case TextInputTarget::phoneNumberKeyboard:   return "phone";
            default:                                     jassertfalse; break;
        }

        return "text";
    }

    void textInputRequired (Point<int>, TextInputTarget& target) override
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard,
                             javaString (getVirtualKeyboardType (target.getKeyboardType())).get());
    }

    void dismissPendingTextInput() override
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, javaString ("").get());

        // updating the nav bar visibility is a bit odd on Android - need to wait for
        if (! isTimerRunning())
            hideNavBarDelayed();
     }

    void hideNavBarDelayed()
    {
        startTimer (500);
    }

    //==============================================================================
    void handlePaintCallback (jobject canvas, jobject paint)
    {
        auto* env = getEnv();

        jobject rect = env->CallObjectMethod (canvas, AndroidCanvas.getClipBounds);
        const int left   = env->GetIntField (rect, AndroidRect.left);
        const int top    = env->GetIntField (rect, AndroidRect.top);
        const int right  = env->GetIntField (rect, AndroidRect.right);
        const int bottom = env->GetIntField (rect, AndroidRect.bottom);
        env->DeleteLocalRef (rect);

        const Rectangle<int> clip (left, top, right - left, bottom - top);

        const int sizeNeeded = clip.getWidth() * clip.getHeight();
        if (sizeAllocated < sizeNeeded)
        {
            buffer.clear();
            sizeAllocated = sizeNeeded;
            buffer = GlobalRef (LocalRef<jobject> ((jobject) env->NewIntArray (sizeNeeded)));
        }
        else if (sizeNeeded == 0)
        {
            return;
        }

        if (jint* dest = env->GetIntArrayElements ((jintArray) buffer.get(), 0))
        {
            {
                Image temp (new PreallocatedImage (clip.getWidth(), clip.getHeight(),
                                                   dest, ! component.isOpaque()));

                {
                    LowLevelGraphicsSoftwareRenderer g (temp);
                    g.setOrigin (-clip.getPosition());
                    g.addTransform (AffineTransform::scale (scale));
                    handlePaint (g);
                }
            }

            env->ReleaseIntArrayElements ((jintArray) buffer.get(), dest, 0);

            env->CallVoidMethod (canvas, AndroidCanvas.drawBitmap, (jintArray) buffer.get(), 0, clip.getWidth(),
                                 (jfloat) clip.getX(), (jfloat) clip.getY(),
                                 clip.getWidth(), clip.getHeight(), true, paint);
        }
    }

    void repaint (const Rectangle<int>& userArea) override
    {
        Rectangle<int> area = userArea * scale;

        if (MessageManager::getInstance()->isThisTheMessageThread())
        {
            view.callVoidMethod (AndroidView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom());
        }
        else
        {
            struct ViewRepainter  : public CallbackMessage
            {
                ViewRepainter (const GlobalRef& view_, const Rectangle<int>& area_)
                    : view (view_), area (area_) {}

                void messageCallback() override
                {
                    view.callVoidMethod (AndroidView.invalidate, area.getX(), area.getY(),
                                         area.getRight(), area.getBottom());
                }

            private:
                GlobalRef view;
                const Rectangle<int> area;
            };

            (new ViewRepainter (view, area))->post();
        }
    }

    void performAnyPendingRepaintsNow() override
    {
        // TODO
    }

    void setAlpha (float /*newAlpha*/) override
    {
        // TODO
    }

    StringArray getAvailableRenderingEngines() override
    {
        return StringArray ("Software Renderer");
    }

    //==============================================================================
    static Point<float> lastMousePos;
    static int64 touchesDown;

    //==============================================================================
    struct StartupActivityCallbackListener : ActivityLifecycleCallbacks
    {
        void onActivityStarted (jobject /*activity*/) override
        {
            auto* env = getEnv();
            LocalRef<jobject> appContext (getAppContext());

            if (appContext.get() != nullptr)
            {

                env->CallVoidMethod (appContext.get(),
                                     AndroidApplication.unregisterActivityLifecycleCallbacks,
                                     activityCallbackListener.get());
                clear();
                activityCallbackListener.clear();

                const_cast<Displays &> (Desktop::getInstance().getDisplays()).refresh();
            }
        }
    };

private:
    //==============================================================================
    GlobalRef view, viewGroup;
    bool viewGroupIsWindow = false;
    GlobalRef buffer;
    bool fullScreen;
    bool navBarsHidden;
    int sizeAllocated;
    float scale;

    //==============================================================================
    #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
     METHOD   (create,                      "<init>",                      "(Landroid/content/Context;ZJ)V") \
     METHOD   (clear,                       "clear",                       "()V") \
     METHOD   (setViewName,                 "setViewName",                 "(Ljava/lang/String;)V") \
     METHOD   (setVisible,                  "setVisible",                  "(Z)V") \
     METHOD   (isVisible,                   "isVisible",                   "()Z") \
     METHOD   (containsPoint,               "containsPoint",               "(II)Z") \
     METHOD   (showKeyboard,                "showKeyboard",                "(Ljava/lang/String;)V") \
     METHOD   (setSystemUiVisibilityCompat, "setSystemUiVisibilityCompat", "(I)V") \
     CALLBACK (handlePaintJni,              "handlePaint",                 "(JLandroid/graphics/Canvas;Landroid/graphics/Paint;)V") \
     CALLBACK (handleMouseDownJni,          "handleMouseDown",             "(JIFFJ)V") \
     CALLBACK (handleMouseDragJni,          "handleMouseDrag",             "(JIFFJ)V") \
     CALLBACK (handleMouseUpJni,            "handleMouseUp",               "(JIFFJ)V") \
     CALLBACK (handleKeyDownJni,            "handleKeyDown",               "(JII)V") \
     CALLBACK (handleKeyUpJni,              "handleKeyUp",                 "(JII)V") \
     CALLBACK (handleBackButtonJni,         "handleBackButton",            "(J)V") \
     CALLBACK (handleKeyboardHiddenJni,     "handleKeyboardHidden",        "(J)V") \
     CALLBACK (viewSizeChangedJni,          "viewSizeChanged",             "(J)V") \
     CALLBACK (focusChangedJni,             "focusChanged",                "(JZ)V") \
     CALLBACK (handleAppPausedJni,          "handleAppPaused",             "(J)V") \
     CALLBACK (handleAppResumedJni,         "handleAppResumed",            "(J)V") \

    DECLARE_JNI_CLASS_WITH_BYTECODE (ComponentPeerView, "com/roli/juce/ComponentPeerView", 16, javaComponentPeerView, sizeof(javaComponentPeerView))
    #undef JNI_CLASS_MEMBERS

    static void JNICALL handlePaintJni          (JNIEnv*, jobject /*view*/, jlong host, jobject canvas, jobject paint)           { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handlePaintCallback (canvas, paint); }
    static void JNICALL handleMouseDownJni      (JNIEnv*, jobject /*view*/, jlong host, jint i, jfloat x, jfloat y, jlong time)  { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleMouseDownCallback (i, Point<float> ((float) x, (float) y), (int64) time); }
    static void JNICALL handleMouseDragJni      (JNIEnv*, jobject /*view*/, jlong host, jint i, jfloat x, jfloat y, jlong time)  { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleMouseDragCallback (i, Point<float> ((float) x, (float) y), (int64) time); }
    static void JNICALL handleMouseUpJni        (JNIEnv*, jobject /*view*/, jlong host, jint i, jfloat x, jfloat y, jlong time)  { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleMouseUpCallback   (i, Point<float> ((float) x, (float) y), (int64) time); }
    static void JNICALL viewSizeChangedJni      (JNIEnv*, jobject /*view*/, jlong host)                                          { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleMovedOrResized(); }
    static void JNICALL focusChangedJni         (JNIEnv*, jobject /*view*/, jlong host, jboolean hasFocus)                       { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleFocusChangeCallback (hasFocus); }
    static void JNICALL handleKeyDownJni        (JNIEnv*, jobject /*view*/, jlong host, jint k, jint kc)                         { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleKeyDownCallback ((int) k, (int) kc); }
    static void JNICALL handleKeyUpJni          (JNIEnv*, jobject /*view*/, jlong host, jint k, jint kc)                         { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleKeyUpCallback ((int) k, (int) kc); }
    static void JNICALL handleBackButtonJni     (JNIEnv*, jobject /*view*/, jlong host)                                          { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleBackButtonCallback(); }
    static void JNICALL handleKeyboardHiddenJni (JNIEnv*, jobject /*view*/, jlong host)                                          { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleKeyboardHiddenCallback(); }
    static void JNICALL handleAppPausedJni      (JNIEnv*, jobject /*view*/, jlong host)                                          { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleAppPausedCallback(); }
    static void JNICALL handleAppResumedJni     (JNIEnv*, jobject /*view*/, jlong host)                                          { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleAppResumedCallback(); }

    //==============================================================================
    friend class Displays;
    static AndroidComponentPeer* frontWindow;
    static GlobalRef activityCallbackListener;

    //==============================================================================
    static constexpr int GRAVITY_LEFT = 0x3, GRAVITY_TOP = 0x30;
    static constexpr int TYPE_APPLICATION = 0x2;
    static constexpr int FLAG_NOT_TOUCH_MODAL = 0x20, FLAG_LAYOUT_IN_SCREEN = 0x100, FLAG_LAYOUT_NO_LIMITS = 0x200;
    static constexpr int PIXEL_FORMAT_OPAQUE = -1, PIXEL_FORMAT_TRANSPARENT = -2;

    struct PreallocatedImage  : public ImagePixelData
    {
        PreallocatedImage (const int width_, const int height_, jint* data_, bool hasAlpha_)
            : ImagePixelData (Image::ARGB, width_, height_), data (data_), hasAlpha (hasAlpha_)
        {
            if (hasAlpha_)
                zeromem (data_, static_cast<size_t> (width * height) * sizeof (jint));
        }

        ~PreallocatedImage()
        {
            if (hasAlpha)
            {
                PixelARGB* pix = (PixelARGB*) data;

                for (int i = width * height; --i >= 0;)
                {
                    pix->unpremultiply();
                    ++pix;
                }
            }
        }

        ImageType* createType() const override                      { return new SoftwareImageType(); }
        LowLevelGraphicsContext* createLowLevelContext() override   { return new LowLevelGraphicsSoftwareRenderer (Image (this)); }

        void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) override
        {
            bm.lineStride = width * static_cast<int> (sizeof (jint));
            bm.pixelStride = static_cast<int> (sizeof (jint));
            bm.pixelFormat = Image::ARGB;
            bm.data = (uint8*) (data + x + y * width);
        }

        ImagePixelData::Ptr clone() override
        {
            PreallocatedImage* s = new PreallocatedImage (width, height, 0, hasAlpha);
            s->allocatedData.malloc (sizeof (jint) * static_cast<size_t> (width * height));
            s->data = s->allocatedData;
            memcpy (s->data, data, sizeof (jint) * static_cast<size_t> (width * height));
            return s;
        }

    private:
        jint* data;
        HeapBlock<jint> allocatedData;
        bool hasAlpha;

        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreallocatedImage)
    };

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer)
};

Point<float> AndroidComponentPeer::lastMousePos;
int64 AndroidComponentPeer::touchesDown = 0;
AndroidComponentPeer* AndroidComponentPeer::frontWindow = nullptr;
GlobalRef AndroidComponentPeer::activityCallbackListener;
AndroidComponentPeer::ComponentPeerView_Class AndroidComponentPeer::ComponentPeerView;

//==============================================================================
ComponentPeer* Component::createNewPeer (int styleFlags, void* nativeWindow)
{
    return new AndroidComponentPeer (*this, styleFlags, nativeWindow);
}

//==============================================================================
bool Desktop::canUseSemiTransparentWindows() noexcept
{
    return true;
}

double Desktop::getDefaultMasterScale()
{
    return 1.0;
}

Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
{
    enum
    {
        ROTATION_0   = 0,
        ROTATION_90  = 1,
        ROTATION_180 = 2,
        ROTATION_270 = 3
    };

    JNIEnv* env = getEnv();
    LocalRef<jstring> windowServiceString (javaString ("window"));


    LocalRef<jobject> windowManager = LocalRef<jobject> (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, windowServiceString.get()));

    if (windowManager.get() != 0)
    {
        LocalRef<jobject> display = LocalRef<jobject> (env->CallObjectMethod (windowManager, AndroidWindowManager.getDefaultDisplay));

        if (display.get() != 0)
        {
            int rotation = env->CallIntMethod (display, AndroidDisplay.getRotation);

            switch (rotation)
            {
                case ROTATION_0:   return upright;
                case ROTATION_90:  return rotatedAntiClockwise;
                case ROTATION_180: return upsideDown;
                case ROTATION_270: return rotatedClockwise;
            }
        }
    }

    jassertfalse;
    return upright;
}

bool MouseInputSource::SourceList::addSource()
{
    addSource (sources.size(), MouseInputSource::InputSourceType::touch);
    return true;
}

bool MouseInputSource::SourceList::canUseTouch()
{
    return true;
}

Point<float> MouseInputSource::getCurrentRawMousePosition()
{
    return AndroidComponentPeer::lastMousePos;
}

void MouseInputSource::setRawMousePosition (Point<float>)
{
    // not needed
}

//==============================================================================
bool KeyPress::isKeyCurrentlyDown (const int /*keyCode*/)
{
    // TODO
    return false;
}

JUCE_API void JUCE_CALLTYPE Process::hide()
{
    auto* env = getEnv();
    LocalRef<jobject> currentActivity (getCurrentActivity().get());

    if (env->CallBooleanMethod (currentActivity.get(), AndroidActivity.moveTaskToBack, true) == 0)
    {
        GlobalRef intent (LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor)));
        env->CallObjectMethod (intent, AndroidIntent.setAction,   javaString ("android.intent.action.MAIN")  .get());
        env->CallObjectMethod (intent, AndroidIntent.addCategory, javaString ("android.intent.category.HOME").get());

        env->CallVoidMethod (currentActivity.get(), AndroidContext.startActivity, intent.get());
    }
}

//==============================================================================
// TODO
JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess() { return true; }
JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (show,                   "show",                 "()V")

DECLARE_JNI_CLASS (AndroidDialog, "android/app/Dialog")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (construct,                   "<init>",                 "(Landroid/content/Context;)V") \
 METHOD (create,                      "create",                 "()Landroid/app/AlertDialog;") \
 METHOD (setTitle,                    "setTitle",               "(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setMessage,                  "setMessage",             "(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setCancelable,               "setCancelable",          "(Z)Landroid/app/AlertDialog$Builder;") \
 METHOD (setOnCancelListener,         "setOnCancelListener",    "(Landroid/content/DialogInterface$OnCancelListener;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setPositiveButton,           "setPositiveButton",      "(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setNegativeButton,           "setNegativeButton",      "(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setNeutralButton,            "setNeutralButton",       "(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;")

DECLARE_JNI_CLASS (AndroidAlertDialogBuilder, "android/app/AlertDialog$Builder")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (dismiss,    "dismiss",  "()V")

DECLARE_JNI_CLASS (AndroidDialogInterface, "android/content/DialogInterface")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \

DECLARE_JNI_CLASS (AndroidDialogOnClickListener, "android/content/DialogInterface$OnClickListener")
#undef JNI_CLASS_MEMBERS

//==============================================================================
class DialogListener  : public juce::AndroidInterfaceImplementer
{
public:
    DialogListener (ModalComponentManager::Callback* callbackToUse, int resultToUse)
        : callback (callbackToUse), result (resultToUse)
    {}

    void onResult (jobject dialog)
    {
        auto* env = getEnv();
        env->CallVoidMethod (dialog, AndroidDialogInterface.dismiss);

        if (callback != nullptr)
            callback->modalStateFinished (result);

        callback = nullptr;
    }

private:
    jobject invoke (jobject proxy, jobject method, jobjectArray args) override
    {
        auto* env = getEnv();
        auto methodName = juce::juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));

        if (methodName == "onCancel" || methodName == "onClick")
        {
            onResult (env->GetObjectArrayElement (args, 0));
            return nullptr;
        }

        // invoke base class
        return AndroidInterfaceImplementer::invoke (proxy, method, args);
    }

    std::unique_ptr<ModalComponentManager::Callback> callback;
    int result;
};

//==============================================================================
static void createAndroidDialog (const String& title, const String& message,
                                 ModalComponentManager::Callback* callback,
                                 const String& positiveButton = {}, const String& negativeButton = {},
                                 const String& neutralButton = {})
{
    auto* env = getEnv();

    LocalRef<jobject> builder (env->NewObject (AndroidAlertDialogBuilder, AndroidAlertDialogBuilder.construct, getMainActivity().get()));

    builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setTitle,   javaString (title).get()));
    builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setMessage, javaString (message).get()));
    builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setCancelable, true));

    builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setOnCancelListener,
                                     CreateJavaInterface (new DialogListener (callback, 0),
                                                          "android/content/DialogInterface$OnCancelListener").get()));

    auto positiveButtonText = positiveButton.isEmpty() ? String ("OK") : positiveButton;

    builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setPositiveButton,
                                     javaString (positiveButtonText).get(),
                                     CreateJavaInterface (new DialogListener (callback, positiveButton.isEmpty() ? 0 : 1),
                                                          "android/content/DialogInterface$OnClickListener").get()));

    if (negativeButton.isNotEmpty())
        builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton,
                                         javaString (negativeButton).get(),
                                         CreateJavaInterface (new DialogListener (callback, neutralButton.isEmpty() ? 0 : 2),
                                                              "android/content/DialogInterface$OnClickListener").get()));

    if (neutralButton.isNotEmpty())
        builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton,
                                         javaString (neutralButton).get(),
                                         CreateJavaInterface (new DialogListener (callback, 0),
                                                              "android/content/DialogInterface$OnClickListener").get()));

    LocalRef<jobject> dialog (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.create));
    env->CallVoidMethod (dialog.get(), AndroidDialog.show);
}

void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
                                                          const String& title, const String& message,
                                                          Component* /*associatedComponent*/,
                                                          ModalComponentManager::Callback* callback)
{
    createAndroidDialog (title, message, callback);
}

bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
                                                      const String& title, const String& message,
                                                      Component* /*associatedComponent*/,
                                                      ModalComponentManager::Callback* callback)
{
    jassert (callback != nullptr); // on android, all alerts must be non-modal!!

    createAndroidDialog (title, message, callback, "OK", "Cancel");
    return false;
}

int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
                                                        const String& title, const String& message,
                                                        Component* /*associatedComponent*/,
                                                        ModalComponentManager::Callback* callback)
{
    jassert (callback != nullptr); // on android, all alerts must be non-modal!!

    createAndroidDialog (title, message, callback, "Yes", "No", "Cancel");
    return 0;
}

int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
                                                   const String& title, const String& message,
                                                   Component* /*associatedComponent*/,
                                                   ModalComponentManager::Callback* callback)
{
    jassert (callback != nullptr); // on android, all alerts must be non-modal!!

    createAndroidDialog (title, message, callback, "Yes", "No");
    return 0;
}

//==============================================================================
static bool androidScreenSaverEnabled = false;

void Desktop::setScreenSaverEnabled (const bool shouldEnable)
{
    constexpr auto FLAG_KEEP_SCREEN_ON = 0x80;

    if (shouldEnable != androidScreenSaverEnabled)
    {
        LocalRef<jobject> activity (getMainActivity());

        if (activity != nullptr)
        {
            auto* env = getEnv();

            LocalRef<jobject> mainWindow (env->CallObjectMethod (activity.get(), AndroidActivity.getWindow));
            env->CallVoidMethod(mainWindow.get(), AndroidWindow.setFlags, shouldEnable ? FLAG_KEEP_SCREEN_ON : 0, FLAG_KEEP_SCREEN_ON);
        }

        androidScreenSaverEnabled = shouldEnable;
    }
}

bool Desktop::isScreenSaverEnabled()
{
    return androidScreenSaverEnabled;
}

//==============================================================================
void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, bool allowMenusAndBars)
{
    ignoreUnused (allowMenusAndBars);

    if (AndroidComponentPeer* peer = dynamic_cast<AndroidComponentPeer*> (kioskComp->getPeer()))
        peer->setFullScreen (enableOrDisable);
    else
        jassertfalse; // (this should have been checked by the caller)
}

//==============================================================================
static jint getAndroidOrientationFlag (int orientations) noexcept
{
    enum
    {
        SCREEN_ORIENTATION_LANDSCAPE          = 0,
        SCREEN_ORIENTATION_PORTRAIT           = 1,
        SCREEN_ORIENTATION_USER               = 2,
        SCREEN_ORIENTATION_REVERSE_LANDSCAPE  = 8,
        SCREEN_ORIENTATION_REVERSE_PORTRAIT   = 9,
        SCREEN_ORIENTATION_USER_LANDSCAPE     = 11,
        SCREEN_ORIENTATION_USER_PORTRAIT      = 12,
    };

    switch (orientations)
    {
        case Desktop::upright:                                          return (jint) SCREEN_ORIENTATION_PORTRAIT;
        case Desktop::upsideDown:                                       return (jint) SCREEN_ORIENTATION_REVERSE_PORTRAIT;
        case Desktop::upright + Desktop::upsideDown:                    return (jint) SCREEN_ORIENTATION_USER_PORTRAIT;
        case Desktop::rotatedAntiClockwise:                             return (jint) SCREEN_ORIENTATION_LANDSCAPE;
        case Desktop::rotatedClockwise:                                 return (jint) SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
        case Desktop::rotatedClockwise + Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_USER_LANDSCAPE;
        default:                                                        return (jint) SCREEN_ORIENTATION_USER;
    }
}

void Desktop::allowedOrientationsChanged()
{
    LocalRef<jobject> activity (getMainActivity());

    if (activity != nullptr)
        getEnv()->CallVoidMethod (activity.get(), AndroidActivity.setRequestedOrientation, getAndroidOrientationFlag (allowedOrientations));
}

//==============================================================================
bool juce_areThereAnyAlwaysOnTopWindows()
{
    return false;
}

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (create,          "<init>",         "()V") \
 FIELD  (density,         "density",        "F") \
 FIELD  (widthPixels,     "widthPixels",    "I") \
 FIELD  (heightPixels,    "heightPixels",   "I")

DECLARE_JNI_CLASS (AndroidDisplayMetrics, "android/util/DisplayMetrics")
#undef JNI_CLASS_MEMBERS

//==============================================================================
class LayoutChangeListener  : public juce::AndroidInterfaceImplementer
{
public:
    virtual void onLayoutChange (LocalRef<jobject> view, int left, int top, int right, int bottom,
                                 int oldLeft, int oldTop, int oldRight, int oldBottom) = 0;

private:
    jobject invoke (jobject proxy, jobject method, jobjectArray args) override
    {
        auto* env = getEnv();
        auto methodName = juce::juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));

        if (methodName == "onLayoutChange")
        {
            jassert (env->GetArrayLength (args) == 9);

            LocalRef<jobject> view (env->GetObjectArrayElement (args, 0));
            int dims[8];

            for (int i = 1; i < 9; ++i)
            {
                LocalRef<jobject> integer (env->GetObjectArrayElement (args, i));
                dims[i - 1] = env->CallIntMethod (integer.get(), JavaInteger.intValue);
            }

            onLayoutChange (std::move (view), dims[0], dims[1], dims[2], dims[3],
                            dims[4], dims[5], dims[6], dims[7]);

            return nullptr;
        }

        // invoke base class
        return AndroidInterfaceImplementer::invoke (proxy, method, args);
    }

    std::unique_ptr<ModalComponentManager::Callback> callback;
};

//==============================================================================
class MainActivityWindowLayoutListener   : public LayoutChangeListener
{
public:
    void onLayoutChange (LocalRef<jobject> /*view*/, int left, int top, int right, int bottom,
                         int oldLeft, int oldTop, int oldRight, int oldBottom) override
    {
        auto newBounds = Rectangle<int>::leftTopRightBottom (left, top, right, bottom);
        auto oldBounds = Rectangle<int>::leftTopRightBottom (oldLeft, oldTop, oldRight, oldBottom);

        if (newBounds != oldBounds)
        {
            auto& displays = Desktop::getInstance().getDisplays();
            auto& mainDisplay = displays.getMainDisplay();

            Rectangle<int> userArea = newBounds / mainDisplay.scale;

            if (userArea != mainDisplay.userArea)
                const_cast<Displays&> (displays).refresh();
        }
    }
};

//==============================================================================
void Displays::findDisplays (float masterScale)
{
    auto* env = getEnv();

    LocalRef<jobject> usableSize (env->NewObject (AndroidPoint, AndroidPoint.create, 0, 0));
    LocalRef<jstring> windowServiceString (javaString ("window"));
    LocalRef<jobject> displayMetrics (env->NewObject (AndroidDisplayMetrics, AndroidDisplayMetrics.create));
    LocalRef<jobject> windowManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, windowServiceString.get()));
    LocalRef <jobject> display (env->CallObjectMethod (windowManager, AndroidWindowManager.getDefaultDisplay));

    jmethodID getRealMetricsMethod = env->GetMethodID (AndroidDisplay, "getRealMetrics", "(Landroid/util/DisplayMetrics;)V");

    if (getRealMetricsMethod != 0)
        env->CallVoidMethod (display.get(), getRealMetricsMethod, displayMetrics.get());
    else
        env->CallVoidMethod (display.get(), AndroidDisplay.getMetrics, displayMetrics.get());

    env->CallVoidMethod (display.get(), AndroidDisplay.getSize, usableSize.get());

    Display d;

    d.isMain = true;
    d.scale = env->GetFloatField (displayMetrics.get(), AndroidDisplayMetrics.density);
    d.dpi = (d.scale * 160.f);
    d.scale *= masterScale;

    d.totalArea = Rectangle<int> (env->GetIntField (displayMetrics.get(), AndroidDisplayMetrics.widthPixels),
                                  env->GetIntField (displayMetrics.get(), AndroidDisplayMetrics.heightPixels)) / d.scale;

    d.userArea = Rectangle<int> (env->GetIntField (usableSize.get(), AndroidPoint.x),
                                 env->GetIntField (usableSize.get(), AndroidPoint.y)) / d.scale;

    // unfortunately usableSize still contains the nav bar
    // the best workaround is to try to get the size of the top-level view of
    // the main activity
    LocalRef<jobject> activity (getMainActivity());

    if (activity != nullptr)
    {
        LocalRef<jobject> mainWindow (env->CallObjectMethod (activity.get(), AndroidActivity.getWindow));
        LocalRef<jobject> decorView (env->CallObjectMethod (mainWindow.get(), AndroidWindow.getDecorView));
        LocalRef<jobject> contentView (env->CallObjectMethod (decorView.get(), AndroidView.findViewById, 0x01020002 /* android.R.id.content */));

        if (contentView != nullptr)
        {
            Rectangle<int> activityArea (env->CallIntMethod (contentView.get(), AndroidView.getLeft),
                                         env->CallIntMethod (contentView.get(), AndroidView.getTop),
                                         env->CallIntMethod (contentView.get(), AndroidView.getWidth),
                                         env->CallIntMethod (contentView.get(), AndroidView.getHeight));

            if (! activityArea.isEmpty())
                d.userArea = activityArea / d.scale;

            static bool hasAddedMainActivityListener = false;

            if (! hasAddedMainActivityListener)
            {
                hasAddedMainActivityListener = true;

                env->CallVoidMethod (contentView.get(), AndroidView.addOnLayoutChangeListener,
                                     CreateJavaInterface (new MainActivityWindowLayoutListener,
                                                          "android/view/View$OnLayoutChangeListener").get());
            }
        }
    }
    else
    {
        // the main activity may have not started yet so add an activity listener
        if (AndroidComponentPeer::activityCallbackListener == nullptr)
        {
            LocalRef<jobject> appContext (getAppContext());

            if (appContext.get() != nullptr)
            {
                AndroidComponentPeer::activityCallbackListener = GlobalRef (CreateJavaInterface (
                        new AndroidComponentPeer::StartupActivityCallbackListener,
                        "android/app/Application$ActivityLifecycleCallbacks"));

                env->CallVoidMethod (appContext.get(),
                                     AndroidApplication.registerActivityLifecycleCallbacks,
                                     AndroidComponentPeer::activityCallbackListener.get());
            }
        }
    }

    displays.add (d);
}

//==============================================================================
Image juce_createIconForFile (const File& /*file*/)
{
    return Image();
}

//==============================================================================
void* CustomMouseCursorInfo::create() const                                                     { return nullptr; }
void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorType)            { return nullptr; }
void MouseCursor::deleteMouseCursor (void* const /*cursorHandle*/, const bool /*isStandard*/)   {}

//==============================================================================
void MouseCursor::showInWindow (ComponentPeer*) const   {}

//==============================================================================
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& /*files*/, const bool /*canMove*/,
                                                           Component* /*srcComp*/, std::function<void()> /*callback*/)
{
    jassertfalse;    // no such thing on Android!
    return false;
}

bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/, Component* /*srcComp*/,
                                                          std::function<void()> /*callback*/)
{
    jassertfalse;    // no such thing on Android!
    return false;
}

//==============================================================================
void LookAndFeel::playAlertSound()
{
}

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getText,      "getText",            "()Ljava/lang/CharSequence;") \
 METHOD (setText,      "setText",            "(Ljava/lang/CharSequence;)V")

DECLARE_JNI_CLASS (AndroidClipboardManager, "android/content/ClipboardManager")
#undef JNI_CLASS_MEMBERS

//==============================================================================
void SystemClipboard::copyTextToClipboard (const String& text)
{
    auto* env = getEnv();

    LocalRef<jobject> clipboardManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, javaString ("clipboard").get()));
    env->CallVoidMethod (clipboardManager.get(), AndroidClipboardManager.setText, javaString(text).get());
}

String SystemClipboard::getTextFromClipboard()
{
    auto* env = getEnv();

    LocalRef<jobject> clipboardManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, javaString ("clipboard").get()));
    LocalRef<jobject> charSequence (env->CallObjectMethod (clipboardManager.get(), AndroidClipboardManager.getText));

    if (charSequence == nullptr)
        return {};

    return juceString(LocalRef<jstring> ((jstring) env->CallObjectMethod(charSequence.get(), JavaCharSequence.toString)));
}

//==============================================================================
const int extendedKeyModifier       = 0x10000;

const int KeyPress::spaceKey        = ' ';
const int KeyPress::returnKey       = 66;
const int KeyPress::escapeKey       = 4;
const int KeyPress::backspaceKey    = 67;
const int KeyPress::leftKey         = extendedKeyModifier + 1;
const int KeyPress::rightKey        = extendedKeyModifier + 2;
const int KeyPress::upKey           = extendedKeyModifier + 3;
const int KeyPress::downKey         = extendedKeyModifier + 4;
const int KeyPress::pageUpKey       = extendedKeyModifier + 5;
const int KeyPress::pageDownKey     = extendedKeyModifier + 6;
const int KeyPress::endKey          = extendedKeyModifier + 7;
const int KeyPress::homeKey         = extendedKeyModifier + 8;
const int KeyPress::deleteKey       = extendedKeyModifier + 9;
const int KeyPress::insertKey       = -1;
const int KeyPress::tabKey          = 61;
const int KeyPress::F1Key           = extendedKeyModifier + 10;
const int KeyPress::F2Key           = extendedKeyModifier + 11;
const int KeyPress::F3Key           = extendedKeyModifier + 12;
const int KeyPress::F4Key           = extendedKeyModifier + 13;
const int KeyPress::F5Key           = extendedKeyModifier + 14;
const int KeyPress::F6Key           = extendedKeyModifier + 16;
const int KeyPress::F7Key           = extendedKeyModifier + 17;
const int KeyPress::F8Key           = extendedKeyModifier + 18;
const int KeyPress::F9Key           = extendedKeyModifier + 19;
const int KeyPress::F10Key          = extendedKeyModifier + 20;
const int KeyPress::F11Key          = extendedKeyModifier + 21;
const int KeyPress::F12Key          = extendedKeyModifier + 22;
const int KeyPress::F13Key          = extendedKeyModifier + 23;
const int KeyPress::F14Key          = extendedKeyModifier + 24;
const int KeyPress::F15Key          = extendedKeyModifier + 25;
const int KeyPress::F16Key          = extendedKeyModifier + 26;
const int KeyPress::F17Key          = extendedKeyModifier + 50;
const int KeyPress::F18Key          = extendedKeyModifier + 51;
const int KeyPress::F19Key          = extendedKeyModifier + 52;
const int KeyPress::F20Key          = extendedKeyModifier + 53;
const int KeyPress::F21Key          = extendedKeyModifier + 54;
const int KeyPress::F22Key          = extendedKeyModifier + 55;
const int KeyPress::F23Key          = extendedKeyModifier + 56;
const int KeyPress::F24Key          = extendedKeyModifier + 57;
const int KeyPress::F25Key          = extendedKeyModifier + 58;
const int KeyPress::F26Key          = extendedKeyModifier + 59;
const int KeyPress::F27Key          = extendedKeyModifier + 60;
const int KeyPress::F28Key          = extendedKeyModifier + 61;
const int KeyPress::F29Key          = extendedKeyModifier + 62;
const int KeyPress::F30Key          = extendedKeyModifier + 63;
const int KeyPress::F31Key          = extendedKeyModifier + 64;
const int KeyPress::F32Key          = extendedKeyModifier + 65;
const int KeyPress::F33Key          = extendedKeyModifier + 66;
const int KeyPress::F34Key          = extendedKeyModifier + 67;
const int KeyPress::F35Key          = extendedKeyModifier + 68;
const int KeyPress::numberPad0      = extendedKeyModifier + 27;
const int KeyPress::numberPad1      = extendedKeyModifier + 28;
const int KeyPress::numberPad2      = extendedKeyModifier + 29;
const int KeyPress::numberPad3      = extendedKeyModifier + 30;
const int KeyPress::numberPad4      = extendedKeyModifier + 31;
const int KeyPress::numberPad5      = extendedKeyModifier + 32;
const int KeyPress::numberPad6      = extendedKeyModifier + 33;
const int KeyPress::numberPad7      = extendedKeyModifier + 34;
const int KeyPress::numberPad8      = extendedKeyModifier + 35;
const int KeyPress::numberPad9      = extendedKeyModifier + 36;
const int KeyPress::numberPadAdd            = extendedKeyModifier + 37;
const int KeyPress::numberPadSubtract       = extendedKeyModifier + 38;
const int KeyPress::numberPadMultiply       = extendedKeyModifier + 39;
const int KeyPress::numberPadDivide         = extendedKeyModifier + 40;
const int KeyPress::numberPadSeparator      = extendedKeyModifier + 41;
const int KeyPress::numberPadDecimalPoint   = extendedKeyModifier + 42;
const int KeyPress::numberPadEquals         = extendedKeyModifier + 43;
const int KeyPress::numberPadDelete         = extendedKeyModifier + 44;
const int KeyPress::playKey         = extendedKeyModifier + 45;
const int KeyPress::stopKey         = extendedKeyModifier + 46;
const int KeyPress::fastForwardKey  = extendedKeyModifier + 47;
const int KeyPress::rewindKey       = extendedKeyModifier + 48;

} // namespace juce
